Sets in Python
A set is an unordered collection of unique values, so it drops duplicates and has no index. You write it in curly braces, such as {1, 2, 3}, or build it with set(), and it answers value in s quickly no matter how big it gets. Sets also combine with union, intersection and difference operations.
Key facts
{3, 1, 2, 3}holds 1, 2 and 3 once each. Duplicates disappear when the set is built.set()creates an empty set.{}creates an empty dictionary.add()puts one value in,remove()raisesKeyErrorfor a missing value, anddiscard()stays silent.list(set(items))removes duplicates from a list, andlist(dict.fromkeys(items))does it without changing the order.a | b,a & b,a - banda ^ bgive the union, intersection, difference and symmetric difference.
What is a set in Python?
A set is an unordered collection of unique values, so it drops duplicates and has no index. You write the values inside curly braces, and Python keeps each value once, however many times you list it. Sets are built for two jobs, testing whether a value is present and removing duplicates, and both stay fast however large the set grows.
numbers = {3, 1, 2, 3, 1}
print(numbers)
print(type(numbers))
print(len(numbers))
print(2 in numbers){1, 2, 3}
<class 'set'>
3
TrueThe five values became three, because the second 3 and the second 1 were duplicates. in works as it does on a list, but a set finds the value by its hash, a number computed from the value, instead of checking items one by one. There is no numbers[0], because the values have no positions.
How do I create a set in Python?
Write the values inside curly braces, or call set() on a list, a string or any other iterable. An empty set must be written as set(), because empty braces {} create an empty dictionary.
letters = set("hello")
print(sorted(letters))
print(len(letters))
empty = set()
print(empty)
print(type(empty))
print(type({}))['e', 'h', 'l', 'o'] 4 set() <class 'set'> <class 'dict'>
set("hello") keeps each letter once, so the two l's collapse into one. The example prints the letters through sorted(), which returns them as an ordered list, because a set of strings can print in a different order each time Python starts.
A set of small whole numbers usually prints in numeric order, which is why the other examples use numbers, but no program should rely on that.
How do I add and remove values in a set?
Call add() with one value, or update() with several. remove() deletes a value and raises KeyError when it isn't there, while discard() deletes it and stays quiet otherwise.
tags = {"python", "web"}
tags.add("css")
tags.add("web")
print(sorted(tags))
tags.update(["html", "js"])
print(len(tags))
tags.remove("web")
tags.discard("ruby")
print(sorted(tags))['css', 'python', 'web'] 5 ['css', 'html', 'js', 'python']
Adding "web" a second time changed nothing, because a set never holds a value twice. update() takes a list, a string or another set and adds every item, so it plays the role that extend() plays for lists. discard("ruby") did nothing without complaint, where remove("ruby") would have raised KeyError: 'ruby'.
How do I remove duplicates from a list in Python?
Convert the list to a set and back with list(set(items)). The set drops the repeats, and list() gives you a list again, though not necessarily in the original order. When the order matters, use list(dict.fromkeys(items)), which keeps the first occurrence of each value where it was.
names = ["bob", "ada", "bob", "cy", "ada"]
unique = list(set(names))
print(len(unique))
print(sorted(unique))
in_order = list(dict.fromkeys(names))
print(in_order)3 ['ada', 'bob', 'cy'] ['bob', 'ada', 'cy']
dict.fromkeys() builds a dictionary with the list's values as keys, and keys can't repeat, so the duplicates vanish while the order of first appearance survives. The set version is shorter and fine whenever you sort the result or only need the count.
What are set operations in Python?
Set operations combine two sets into a new one. The union holds every value from either set, the intersection holds the values in both, the difference holds the values in the first set but not the second, and the symmetric difference holds the values in exactly one of them. Each has an operator and a method with the same result.
| Operation | Operator | Method | Result |
|---|---|---|---|
| Union | a | b | a.union(b) | Values in a, in b, or in both |
| Intersection | a & b | a.intersection(b) | Values in both a and b |
| Difference | a - b | a.difference(b) | Values in a that are not in b |
| Symmetric difference | a ^ b | a.symmetric_difference(b) | Values in a or b but not both |
a = {1, 2, 3, 4}
b = {3, 4, 5}
print(a | b)
print(a & b)
print(a - b)
print(a ^ b)
print(a.union(b))
print(a.intersection(b)){1, 2, 3, 4, 5}
{3, 4}
{1, 2}
{1, 2, 5}
{1, 2, 3, 4, 5}
{3, 4}The operators need sets on both sides, while the methods accept any iterable, so a.union([5, 6]) works and a | [5, 6] raises TypeError. A set comprehension builds a set the way a list comprehension builds a list, with curly braces instead of square brackets.
squares = {n * n for n in range(5)}
print(squares)
print(16 in squares)
print(len(squares)){0, 1, 4, 9, 16}
True
5What is the difference between a set and a list?
A set holds each value once and has no order, and a list holds values in order, duplicates included. Use a set when you need uniqueness or fast membership tests, and a list when the order or the position of items matters.
| Type | Written as | Duplicates | Ordered | Use it when |
|---|---|---|---|---|
| Set | Curly braces, {1, 2, 3} | No | No, and no indexing | You need membership tests or unique values |
| List | Square brackets, [1, 2, 3] | Yes | Yes, with items[0] | The order and position of items matter |
value in a_set takes about the same time whether the set holds ten values or a million, because the hash points straight at the value. The same test on a list checks the items one after another, so it slows down as the list grows. For a handful of items the difference is invisible, and a list is the default choice until you need what a set offers.
Should I use a list, a tuple, a set or a dictionary?
Pick by asking three questions. Do the values need names, can they change, and do duplicates matter? A list is the default for an ordered group of values, a tuple for a fixed group, a set for unique values, and a dictionary for values you look up by key.
| Type | Written as | Ordered | Can change | Duplicates | Use it when |
|---|---|---|---|---|---|
| List | [1, 2, 2] | Yes | Yes | Yes | An ordered collection that grows, shrinks or gets sorted |
| Tuple | (1, 2, 2) | Yes | No | Yes | A fixed group of related values, or a dictionary key |
| Set | {1, 2} | No | Yes | No | Unique values and fast membership tests |
| Dictionary | {"a": 1} | Yes | Yes | Keys no, values yes | Values looked up by a name |
Which set methods will I use most?
The set methods you will reach for are the ones that add, remove, combine and compare. The table lists them, and the four operations have both a method and an operator. frozenset() builds a set that can't be changed and can therefore be a dictionary key or an item of another set.
| Method | What it does |
|---|---|
add(x) | Adds x |
remove(x) | Removes x, or raises KeyError when it is missing |
discard(x) | Removes x when present, and does nothing otherwise |
pop() | Removes and returns an arbitrary value |
clear() | Removes every value |
update(iterable) | Adds every item of the iterable |
copy() | Returns a new set with the same values |
union(other) | Returns the values in either set, the same as a | b |
intersection(other) | Returns the values in both sets, the same as a & b |
difference(other) | Returns the values in this set but not the other, the same as a - b |
symmetric_difference(other) | Returns the values in exactly one of the sets, the same as a ^ b |
issubset(other) | True when every value of this set is in the other, the same as a <= b |
issuperset(other) | True when this set holds every value of the other, the same as a >= b |
isdisjoint(other) | True when the two sets share no values |
Python has a few more, such as difference_update(), that change the set in place instead of returning a new one.
Common mistakes with sets in Python
These four mistakes with sets are the common ones. Three stop the program with a message, and the first creates the wrong type without a word.
- Writing {} for an empty set.
{}is an empty dictionary, andadd()then fails withAttributeError: 'dict' object has no attribute 'add'. Writeset(). - TypeError: 'set' object is not subscriptable. Code tried
s[0], and a set has no positions. Loop over the set, or convert it withsorted()when you need an order. - KeyError: 99.
remove()was given a value that isn't in the set. Usediscard(), or test withinfirst. - TypeError: cannot use 'list' as a set element (unhashable type: 'list'). A list was added to a set. Set values must be hashable, which means Python can compute their hash, and it can't for a value that could change, so use a tuple instead.
Run the three broken programs to see the messages, then fix them in the editor.
s = {1, 2, 3}
print(s[0])Traceback (most recent call last):
File "main.py", line 2, in <module>
print(s[0])
~^^^
TypeError: 'set' object is not subscriptables = {1, 2, 3}
s.remove(99)Traceback (most recent call last):
File "main.py", line 2, in <module>
s.remove(99)
~~~~~~~~^^^^
KeyError: 99s = set()
s.add([1, 2])Traceback (most recent call last):
File "main.py", line 2, in <module>
s.add([1, 2])
~~~~~^^^^^^^^
TypeError: cannot use 'list' as a set element (unhashable type: 'list')Exercise
Turn the list into a set so each address counts once, then print how many unique addresses there are and the unique addresses in sorted order, giving 3 and ['a@x.com', 'b@x.com', 'c@x.com']. The starter counts and sorts the whole list, repeats included.
emails = ["a@x.com", "b@x.com", "a@x.com", "c@x.com", "b@x.com"]
print(len(emails))
print(sorted(emails))
3 ['a@x.com', 'b@x.com', 'c@x.com']
Show the solution
emails = ["a@x.com", "b@x.com", "a@x.com", "c@x.com", "b@x.com"]
unique = set(emails)
print(len(unique))
print(sorted(unique))
Quiz
This quiz has 5 questions. Pick an answer to see why it is right or wrong.
-
1What does this program print?
print(len({1, 2, 2, 3}))A set holds each value once, so the repeated 2 is dropped and three values remain. Counting the four values as written is the mistake to avoid.
-
2What does this program print?
print(type({}))Empty curly braces make an empty dictionary, not an empty set. An empty set is written set().
-
3What does this program print?
print(sorted({1, 2, 3} & {2, 3, 4}))The & operator gives the intersection, the values found in both sets, and sorted() lists them in order. The union with every value would come from |.
-
4Which expression creates an empty set?
Only set() creates an empty set. Empty braces make a dictionary, brackets make a list, and parentheses make a tuple.
-
5What does this program print?
s = {1, 2} s.add(2) print(len(s))Adding a value the set already holds changes nothing, so the set still has two values. add() never raises an error for a duplicate.