Set Union, Intersection, Difference
Learn to manipulate Python sets with union, intersection, and difference operations in this hands-on tutorial. Step-by-step walkthrough with troubleshooting.
Focus: manipulate sets with union, intersection, difference
You've mastered lists and dictionaries, but what happens when you need to work with unique elements and perform mathematical set operations like finding common items or differences between groups? Without union, intersection, and difference, you'd be stuck writing slow loops and complex condition checks. Python's built-in set type gives you these operations at blazing speed, turning common data problems into elegant one-liners.
The problem this lesson solves
Imagine you're building a social network feature: you need to find mutual friends (common elements) between two users, suggest new friends who are in one network but not the other, or combine two friend lists without duplicates. Without set operations, you'd write something like:
list1 = ["alice", "bob", "charlie"]
list2 = ["bob", "dave", "eve"]
# Manual union (no duplicates)
combined = list1.copy()
for item in list2:
if item not in combined:
combined.append(item)
# Manual intersection
common = []
for item in list1:
if item in list2:
common.append(item)
# Manual difference
unique_to_list1 = []
for item in list1:
if item not in list2:
unique_to_list1.append(item)
This code is verbose, error-prone, and slow (O(nm) for intersection). Worse, it's hard to read and maintain. Python sets solve all three problems with mathematically precise, highly optimized* operations.
Core concept / mental model
Think of a set as a bag of unique items, like a guest list where nobody's name appears twice. The three core operations are:
- Union: Pour both bags together, keep only one copy of each item. Result contains all items from both sets.
- Intersection: Find items that appear in both bags simultaneously. Result contains only the shared items.
- Difference: Take items from the first bag that are not in the second bag. Result contains items unique to the first set.
Formal definitions (for clarity)
| Operation | Symbol | Py method / operator | Result contains... |
|---|---|---|---|
| Union | A ∪ B | A.union(B) or A | B |
All unique elements from A and B |
| Intersection | A ∩ B | A.intersection(B) or A & B |
Elements present in both A and B |
| Difference | A – B | A.difference(B) or A – B |
Elements in A but not in B |
Pro tip: Sets are unordered — don't rely on insertion order. Use sets when uniqueness and membership tests matter; use lists when order matters.
How it works step by step
-
Create sets from lists or directly with
set()or curly braces:my_set = {1, 2, 3}. Remember: empty braces{}create a dict, not a set. Useset()for an empty set. -
Call the method or use the operator:
set1.union(set2)orset1 | set2. Both work identically. Methods accept any iterable; operators require both operands to be sets. -
Capture the result: These operations return a new set — they do not modify the original sets. If you want to modify a set in place, use update variants:
union_update()(or|=),intersection_update()(&=),difference_update()(-=).
In-place vs. copy
| Operation | Returns new set | Modifies in place |
|---|---|---|
| Union | A.union(B), A | B |
A.update(B), A |= B |
| Intersection | A.intersection(B), A & B |
A.intersection_update(B), A &= B |
| Difference | A.difference(B), A – B |
A.difference_update(B), A -= B |
Pro tip: Use the operator syntax (
|,&,-) for readability; use methods when you need to pass a list or tuple as the other argument.
Hands-on walkthrough
Let's apply this to a realistic scenario: we have two guest lists for a conference — VIPs and workshop attendees. We'll find: - All guests combined (union). - Guests who are both VIPs and attending workshops (intersection). - VIPs who are not attending any workshop (difference).
# Example 1: Basic set operations
vips = {"Alice", "Bob", "Charlie", "Diana"}
workshop_attendees = {"Bob", "Diana", "Eve", "Frank"}
# Union: all unique guests
all_guests = vips | workshop_attendees
print(f"All guests: {all_guests}")
# Output (order may vary): All guests: {'Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank'}
# Intersection: guests doing both
both = vips & workshop_attendees
print(f"Both VIP and workshop: {both}")
# Output (order may vary): Both VIP and workshop: {'Bob', 'Diana'}
# Difference: VIPs skipping workshop
vips_only = vips - workshop_attendees
print(f"VIPs not attending: {vips_only}")
# Output (order may vary): VIPs not attending: {'Alice', 'Charlie'}
# Difference: workshop-only guests
workshop_only = workshop_attendees - vips
print(f"Workshop-only: {workshop_only}")
# Output (order may vary): Workshop-only: {'Eve', 'Frank'}
# Example 2: Using methods with non-set iterables
checked_in = ["Alice", "Bob", "Charlie"] # list (may contain duplicates?)
registered = {"Bob", "Diana", "Eve"} # set
# Union: method accepts list
all_attendees = registered.union(checked_in)
print(f"All attendees: {all_attendees}")
# Output (order may vary): All attendees: {'Alice', 'Bob', 'Charlie', 'Diana', 'Eve'}
# Intersection: method accepts list
active_registered = registered.intersection(checked_in)
print(f"Checked in and registered: {active_registered}")
# Output (order may vary): Checked in and registered: {'Bob'}
# Example 3: In-place operations (modify original set)
vips = {"Alice", "Bob", "Charlie"}
early_birds = {"Alice", "Diana"}
# Add early birds to VIPs in place (union update)
vips |= early_birds
print(vips) # Output: {'Alice', 'Bob', 'Charlie', 'Diana'}
# Remove early birds from VIPs in place (difference update)
vips -= early_birds
print(vips) # Output: {'Bob', 'Charlie'}
# Keep only those in both (intersection update)
vips &= {"Bob", "Eve"}
print(vips) # Output: {'Bob'}
Compare options / when to choose what
| Scenario | Best operation | Why |
|---|---|---|
| Combine two lists of unique customers | union (or |) |
No duplicates, fast membership |
| Find items common to both datasets | intersection (or &) |
Single line, O(min(len(a), len(b))) |
| Find missing values from one list | difference (or -) |
Exact set of exclusions |
| Combine many sets at once | union(*sets) |
No chaining needed |
| Need to keep duplicates? | Use lists, not sets | Sets discard duplicates |
| Need ordered result? | Convert back to list: list(result) |
Sets are unordered |
Pro tip: For symmetric difference (items in A or B but not both), use
A ^ BorA.symmetric_difference(B). This is like "exclusive or" for sets.
Troubleshooting & edge cases
- Empty sets: All operations work fine with empty sets.
{1, 2} & set()returnsset(). - Mutable elements: Sets can only contain hashable elements (strings, numbers, tuples). Lists, dicts, or other sets will raise
TypeError: unhashable type. - Order not guaranteed: Don't rely on insertion order. Use sorted() if you need consistent output:
sorted(result). - Operator precedence:
|and&have lower precedence than comparison operators. Use parentheses:(a | b) & cvsa | b & c(which Python interprets asa | (b & c)). - Modifying while iterating: You can't add or remove elements from a set while iterating over it. Create a copy or collect items to add/remove in a separate list.
# Common mistake: Unhashable type
# bad_set = {[1, 2], [3, 4]} # TypeError: unhashable type: 'list'
# Correct way: use tuples
correct_set = {(1, 2), (3, 4)}
# Modifying during iteration — wrong
my_set = {1, 2, 3}
# for item in my_set:
# my_set.add(item + 10) # RuntimeError: Set changed size during iteration
# Correct approach: iterate over a copy
for item in my_set.copy():
my_set.add(item + 10)
print(my_set) # Output: {1, 2, 3, 11, 12, 13}
What you learned & what's next
You now know how to:
- Explain the core idea behind set union, intersection, and difference as mathematical operations for unique elements.
- Apply these operations using both operators (|, &, -) and methods (.union(), .intersection(), .difference()).
- Choose between creating new sets vs. modifying in place with update variants.
- Avoid common pitfalls like unhashable elements or iteration-modification conflicts.
These operations are fundamental to data cleaning, permission systems, tagging, and any application where you need to compare groups. In the next lesson, you'll build on this foundation by learning set comprehensions — a powerful syntax for creating sets inline, much like list comprehensions but with automatic deduplication.
Practice today: rewrite the manual friend-matching code from the beginning using proper set operations. You'll see how three lines replace twenty.
Practice recap
Try this: create three sets — a = {1, 2, 3, 4}, b = {3, 4, 5, 6}, c = {5, 6, 7, 8}. Compute the union of all three, the intersection of a and c, and the difference of b from a. Then print each result sorted. You'll see how to handle multiple sets in one expression.
Common mistakes
- Using
{}to create an empty set — creates an empty dict instead. Always useset()for an empty set. - Assuming sets preserve insertion order — they don't. Use
sorted()or switch to lists if order matters. - Forgetting operator precedence:
a | b & cis parsed asa | (b & c), not(a | b) & c. Add parentheses. - Trying to store mutable elements (list, dict, set) inside a set — raises
TypeError: unhashable type. Use tuples instead.
Variations
- Use
frozensetfor an immutable, hashable set that can itself be a set element or dictionary key. - For symmetric difference (items in A or B but not both), use
A ^ BorA.symmetric_difference(B)— helpful for finding unique disagreements. - Chain multiple operations:
(a | b) – (c & d)— but use parentheses for clarity, even when not strictly needed.
Real-world use cases
- Finding mutual followers between two Twitter accounts by intersecting their follower sets.
- Cleaning a list of user input tags by converting to a set (removes duplicates) then applying union to merge from multiple sources.
- Computing which IP addresses are in a whitelist but not in a blacklist using difference, for firewall rules.
Key takeaways
- Use
|for union,&for intersection,-for difference — they're fast and readable. - Sets store only unique elements and require all items to be hashable (strings, numbers, tuples).
- Operators require both operands to be sets; methods accept any iterable as the argument.
- Use in-place operators (
|=,&=,-=) to modify the original set without creating a new one. - Sets are unordered — don't rely on insertion order; convert to sorted list if needed.
- Always use
set()for an empty set, never{}.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.