Set Operations: Union, Intersection and Difference
Four operations answer four everyday questions: what is in either, what is in both, what is only in the first, and what is in exactly one.
- The four operations
- Operators and methods
- Updating in place
- Comparing sets
- Practical uses
- What changed between two versions
- Common and unique interests
- Validating required fields
- Permission checks
- Deduplicating across sources
- Finding the common words in several documents
- Cost
- Common mistakes
- Best practices
- Practice
- Conclusion
- Basics
- Data Types
- Operators
- Strings
- Control Flow
- Lists
- Tuples
- Sets
- Dictionaries
- Comprehensions
- Functions
- Advanced Functions
- Recursion
- Exception Handling
- File Handling
- Modules
- Standard Library
- OOP
- Advanced OOP
- Iterators and Generators
- Decorators
- Context Managers
- Descriptors and Dataclasses
- Python Internals
- Concurrency
- Regular Expressions
- Serialization
- Command Line Python
- Testing and Debugging
- Type Hints
- Performance
- Python Security
- DSA with Python
The four operations
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # {1, 2, 3, 4, 5, 6} union - in either
print(a & b) # {3, 4} intersection - in both
print(a - b) # {1, 2} difference - in a only
print(b - a) # {5, 6} difference - in b only
print(a ^ b) # {1, 2, 5, 6} symmetric difference - in exactly one a b
.---------. .---------.
| 1 2 | 3 4 | 5 6 |
'---------' '---------'
a | b -> 1 2 3 4 5 6 everything
a & b -> 3 4 the overlap
a - b -> 1 2 left only
a ^ b -> 1 2 5 6 everything except the overlapOperators and methods
| Operation | Operator | Method | Method accepts |
|---|---|---|---|
| Union | a | b | a.union(b) | Any iterable |
| Intersection | a & b | a.intersection(b) | Any iterable |
| Difference | a - b | a.difference(b) | Any iterable |
| Symmetric difference | a ^ b | a.symmetric_difference(b) | Any iterable |
a = {1, 2, 3}
print(a.union([3, 4])) # {1, 2, 3, 4} - a list is accepted
# print(a | [3, 4]) # TypeError - the operator needs a set
print(a.intersection([2, 3], (3, 9))) # {3} - several iterables at onceThe operators require both sides to be sets. The methods accept any iterable, which is often more convenient.
Updating in place
a = {1, 2, 3}
a |= {4} # or a.update({4})
print(a) # {1, 2, 3, 4}
a &= {2, 3, 4, 9} # or a.intersection_update(...)
print(a) # {2, 3, 4}
a -= {4} # or a.difference_update({4})
print(a) # {2, 3}
a ^= {3, 5} # or a.symmetric_difference_update(...)
print(a) # {2, 5}Comparing sets
small = {1, 2}
large = {1, 2, 3, 4}
other = {9}
print(small <= large) # True - subset
print(small.issubset(large)) # True
print(small < large) # True - proper subset (not equal)
print(large >= small) # True - superset
print(large.issuperset(small)) # True
print(small.isdisjoint(other)) # True - no elements in common
print({1, 2} == {2, 1}) # True - order is irrelevantPractical uses
What changed between two versions
before = {"index.html", "style.css", "app.js"}
after = {"index.html", "style.css", "app.js", "logo.svg"}
print("added: ", after - before) # {'logo.svg'}
print("removed:", before - after) # set()
print("kept: ", before & after)Common and unique interests
meera = {"python", "sql", "design"}
arun = {"python", "javascript", "design"}
print("both: ", meera & arun) # {'python', 'design'}
print("either: ", meera | arun)
print("only meera:", meera - arun) # {'sql'}
print("not shared:", meera ^ arun) # {'sql', 'javascript'}Validating required fields
required = {"name", "email", "phone"}
submitted = {"name", "email"}
missing = required - submitted
extra = submitted - required
if missing:
print("missing fields:", ", ".join(sorted(missing)))
if extra:
print("unexpected fields:", ", ".join(sorted(extra)))Permission checks
user_roles = {"editor", "reviewer"}
allowed_roles = {"admin", "editor"}
if user_roles & allowed_roles:
print("access granted")
if user_roles.isdisjoint(allowed_roles):
print("no overlap at all")
if {"admin"} <= user_roles:
print("is an administrator")Deduplicating across sources
list_a = ["a@x.com", "b@x.com"]
list_b = ["b@x.com", "c@x.com"]
all_addresses = set(list_a) | set(list_b)
duplicates = set(list_a) & set(list_b)
print(sorted(all_addresses)) # ['a@x.com', 'b@x.com', 'c@x.com']
print(duplicates) # {'b@x.com'}Finding the common words in several documents
docs = [
"the quick brown fox",
"the lazy brown dog",
"the brown bear",
]
word_sets = [set(doc.split()) for doc in docs]
common = set.intersection(*word_sets)
print(sorted(common)) # ['brown', 'the']
anywhere = set.union(*word_sets)
print(len(anywhere))Cost
| Operation | Roughly |
|---|---|
x in s, add, discard | Constant |
a | b, a ^ b | Proportional to the total size |
a & b, a - b | Proportional to the smaller set |
Common mistakes
- Using
|with a list on one side. Use the method form. - Confusing
a - bwithb - a; difference is not symmetric. - Expecting
^to mean "in both". It means the opposite. - Using
<and thinking it compares sizes. It tests subset. - Forgetting that these operators mean bitwise arithmetic on integers.
- Expecting the result of a set operation to preserve any order.
Best practices
- Use operators when both sides are sets, methods when one side is a list or a generator.
- Use
isdisjointrather than testing whether the intersection is empty; it can stop early. - Name the result of a set operation:
missing = required - submittedreads by itself. - Sort before displaying, always.
Practice
- Given three lists of student names per subject, find those enrolled in all three and those in exactly one.
- Report which required configuration keys are missing and which are unrecognised.
- Explain the difference between
a - b,b - aanda ^ bwith a concrete example. - Use
set.intersection(*sets)to find words common to five sentences. - Explain why
{1, 2} < {1, 2}isFalsebut{1, 2} <= {1, 2}isTrue.
Conclusion
Union, intersection, difference and symmetric difference answer four questions you will ask constantly: everything, the overlap, what is only here, and what is not shared. Naming the result of each operation turns set code into something that reads like the requirement it implements.