CollectionsChapter 36 of 114
Sets
An unordered collection with no duplicates, and fast membership tests.
Curly brackets, no duplicates
numbers = {1, 2, 2, 3}
print(numbers)
print(len(numbers))Output
{1, 2, 3}
3The duplicate vanished on the way in. Sets are unordered, so do not rely on the order things print in — sort when you need a stable display.
words = {"grace", "ada", "katherine"}
print(sorted(words))Output
['ada', 'grace', 'katherine']
The empty set is not {}
print(type({}))
print(type(set()))Output
<class 'dict'> <class 'set'>
{} was a dictionary first. set() is the only way to write an empty one.
Removing duplicates
The everyday use, and the reason most people meet sets at all:
names = ["Ada", "Grace", "Ada", "Katherine"]
unique = list(set(names))
print(len(unique))
print(sorted(unique))Output
3 ['Ada', 'Grace', 'Katherine']
names = ["Ada", "Grace", "Ada", "Katherine"]
print(list(dict.fromkeys(names)))Output
['Ada', 'Grace', 'Katherine']
Membership is fast
in on a list checks every item. On a set it goes straight there, so for repeated lookups over a lot of data, a set is the right shape:
allowed = {"read", "write"}
print("read" in allowed)
print("delete" in allowed)Output
True False
Adding and removing
tags = {"python"}
tags.add("tutorial")
tags.update(["free", "python"])
print(sorted(tags))
tags.discard("missing")
tags.remove("free")
print(sorted(tags))Output
['free', 'python', 'tutorial'] ['python', 'tutorial']
remove() raises when the item is absent; discard() does not. Choose by whether absence is a problem.
Comparing sets
This is what sets are really for:
a = {1, 2, 3}
b = {3, 4}
print(sorted(a | b))
print(sorted(a & b))
print(sorted(a - b))
print(sorted(a ^ b))Output
[1, 2, 3, 4] [3] [1, 2] [1, 2, 4]
| Operator | Method | Gives | |
|---|---|---|---|
| `\ | ` | union | in either |
& | intersection | in both | |
- | difference | in the first only | |
^ | symmetric_difference | in one but not both |
"Which users are in the new list but not the old one" is a set difference, and writing it any other way is more work.
before = {"ada", "grace"}
after = {"grace", "katherine"}
print("joined:", sorted(after - before))
print("left:", sorted(before - after))Output
joined: ['katherine'] left: ['ada']
Subsets
print({1, 2} <= {1, 2, 3})
print({1, 5}.isdisjoint({2, 3}))Output
True True
What a set can hold
Only hashable items, which in practice means no lists or dictionaries inside:
try:
{[1, 2]}
except TypeError:
print("a list cannot go in a set")
print(sorted({(1, 2), (3, 4)}))Output
a list cannot go in a set [(1, 2), (3, 4)]
Test yourself
3 questionsWhat is type({})?
Show the answer
dict — The empty curly brackets were a dictionary first. Write set() for an empty set.
What does a - b give for sets?
Show the answer
Items in a but not in b — Difference is the natural way to write questions like 'who is new since last time'.
What is lost when you use list(set(names)) to remove duplicates?
Show the answer
The order — Sets are unordered. list(dict.fromkeys(names)) removes duplicates and keeps first-seen order.
Dictionaries
Look values up by a key instead of a position.