Chapters
Python114 chapters

CollectionsChapter 36 of 114

Sets

An unordered collection with no duplicates, and fast membership tests.

Curly brackets, no duplicates

Python
numbers = {1, 2, 2, 3}
print(numbers)
print(len(numbers))

Output

{1, 2, 3}
3

The 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.

Python
words = {"grace", "ada", "katherine"}
print(sorted(words))

Output

['ada', 'grace', 'katherine']

The empty set is not {}

Python
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:

Python
names = ["Ada", "Grace", "Ada", "Katherine"]
unique = list(set(names))
print(len(unique))
print(sorted(unique))

Output

3
['Ada', 'Grace', 'Katherine']
Python
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:

Python
allowed = {"read", "write"}
print("read" in allowed)
print("delete" in allowed)

Output

True
False

Adding and removing

Python
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:

Python
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]
OperatorMethodGives
`\`unionin either
&intersectionin both
-differencein the first only
^symmetric_differencein 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.

Python
before = {"ada", "grace"}
after = {"grace", "katherine"}
print("joined:", sorted(after - before))
print("left:", sorted(before - after))

Output

joined: ['katherine']
left: ['ada']

Subsets

Python
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:

Python
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 questions

What 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.

Next chapter

Dictionaries

Look values up by a key instead of a position.