Sets

Python · Lesson 19 of 43 6 min read Updated

How many different cities did your customers order from? Which students joined both the cricket team and the coding club? Which skills does a job need that you do not have yet? These are questions about unique values and about what two groups share, and Python's set type answers them in a single line.

In this lesson you will create sets, use them to remove duplicates and to test membership quickly, add and remove items, combine sets with union, intersection and difference, and meet the unchangeable frozenset.

Creating a set

A set is an unordered collection of unique values, written in curly braces. If you add a value that is already there, nothing happens.

PythonRun it yourself
cities = {"Pune", "Kochi", "Pune", "Jaipur", "Kochi"}
print(len(cities))
print(sorted(cities))

orders = ["Rohtak", "Lucknow", "Rohtak", "Pune", "Lucknow", "Rohtak"]
unique_cities = set(orders)
print(len(unique_cities), "different cities")
print("Pune" in unique_cities)
Output
3
['Jaipur', 'Kochi', 'Pune']
3 different cities
True

Two important facts:

  • Sets have no order. When you print a set, the items can appear in any order, and that order can even change between runs. That is why these examples print sorted(...). For the same reason, sets have no index: cities[0] gives TypeError: 'set' object is not subscriptable.
  • {} is not an empty set. Empty curly braces make an empty dictionary. Write set() for an empty set.

Set items must be hashable (unchangeable values such as numbers, strings and tuples). You cannot put a list inside a set.

Removing duplicates

set(items) is the quickest way to remove duplicates. But it throws away the original order. If order matters, use dict.fromkeys(), which keeps the first appearance of each value, because dictionaries remember insertion order:

PythonRun it yourself
attendance = ["Isha", "Rohan", "Isha", "Aarav", "Rohan", "Meera"]

print(len(set(attendance)), "different students")
print(list(dict.fromkeys(attendance)))
Output
4 different students
['Isha', 'Rohan', 'Aarav', 'Meera']

Fast membership tests

Checking x in some_list looks at the items one by one, so it gets slower as the list grows. Checking x in some_set uses the hash and takes about the same time whether the set has ten items or ten million. If you check membership many times, for example against a list of blocked usernames or valid PIN codes, convert the list to a set once and test against the set.

Adding and removing items

Sets are mutable, so you can add and remove items:

PythonRun it yourself
skills = {"Python", "Excel"}

skills.add("SQL")
skills.add("Python")          # already there, nothing changes
skills.update(["Git", "HTML"])
print(sorted(skills))

skills.discard("Excel")
skills.discard("Java")        # not there, no error
print(sorted(skills))
Output
['Excel', 'Git', 'HTML', 'Python', 'SQL']
['Git', 'HTML', 'Python', 'SQL']
  • add(x) adds one item; update(iterable) adds many.
  • discard(x) removes an item if it is there and does nothing otherwise.
  • remove(x) also removes an item, but raises KeyError if it is missing. Use it when a missing item would be a bug you want to hear about.

Set operations

This is where sets shine. Python gives you the operations from school maths with simple operators:

OperatorMethodResult
a | ba.union(b)Items in either set
a & ba.intersection(b)Items in both sets
a - ba.difference(b)Items in a but not in b
a ^ ba.symmetric_difference(b)Items in exactly one of the sets
a <= ba.issubset(b)True if every item of a is in b
PythonRun it yourself
cricket = {"Aarav", "Kabir", "Rohan", "Farhan"}
coding = {"Kabir", "Isha", "Meera", "Rohan"}

print("Both clubs:", sorted(cricket & coding))
print("Either club:", sorted(cricket | coding))
print("Cricket only:", sorted(cricket - coding))
print("Exactly one club:", sorted(cricket ^ coding))
print({"Kabir", "Rohan"} <= cricket)
Output
Both clubs: ['Kabir', 'Rohan']
Either club: ['Aarav', 'Farhan', 'Isha', 'Kabir', 'Meera', 'Rohan']
Cricket only: ['Aarav', 'Farhan']
Exactly one club: ['Aarav', 'Farhan', 'Isha', 'Meera']
True

Without sets, each of these lines would need a loop and a few if statements. The method versions, such as cricket.union(coding), do the same job and also accept a list or any other iterable, while the operators need sets on both sides.

A practical example

A job posting asks for some skills, and a candidate has others. Sets answer "what is missing?" and "how good is the match?" in two lines:

PythonRun it yourself
required = {"Python", "SQL", "Git", "Pandas"}
priya = {"Python", "Excel", "SQL", "Communication"}

missing = required - priya
match = len(required & priya) / len(required)

print("Missing:", sorted(missing))
print(f"Match: {match:.0%}")
Output
Missing: ['Git', 'Pandas']
Match: 50%

frozenset: a set that cannot change

A frozenset is an immutable set: no add(), no discard(). Because it cannot change, it is hashable, so it can be a dictionary key or an item inside another set, which a normal set cannot. Create one with frozenset(["Python", "SQL"]). You will not need it often, but now you will recognise it.

Common mistakes

  • Writing {} for an empty set. It creates a dictionary. Use set().
  • Expecting a set to keep order. Print sorted(my_set) when order matters, or use dict.fromkeys() to remove duplicates in order.
  • Indexing a set. my_set[0] fails. Loop over it, or convert it to a sorted list first.
  • Using remove() when the item may be missing. It raises KeyError. Use discard().

Key points

  • A set stores unique, hashable values in no particular order; set() is an empty set.
  • set(items) removes duplicates; dict.fromkeys(items) removes them and keeps order.
  • x in a_set is fast, even for very large sets.
  • add(), update(), discard() and remove() change a set.
  • |, &, - and ^ give union, intersection, difference and symmetric difference.
  • frozenset is an immutable, hashable set.

Exercise

Two shops in Lucknow sell these items: shop_a = ["rice", "dal", "tea", "sugar", "tea", "oil"] and shop_b = ["tea", "coffee", "oil", "biscuits", "dal"]. Convert both lists to sets and print, in sorted order: the items both shops sell, the items only shop A sells, and every item you can buy in either shop. Finally print how many different items there are in total.

Show solution
Python
shop_a = ["rice", "dal", "tea", "sugar", "tea", "oil"]
shop_b = ["tea", "coffee", "oil", "biscuits", "dal"]

a = set(shop_a)
b = set(shop_b)

print("Both:", sorted(a & b))
print("Only A:", sorted(a - b))
all_items = a | b
print("Either:", sorted(all_items))
print(len(all_items), "different items")
Output
Both: ['dal', 'oil', 'tea']
Only A: ['rice', 'sugar']
Either: ['biscuits', 'coffee', 'dal', 'oil', 'rice', 'sugar', 'tea']
7 different items

Converting to sets removes the duplicate "tea" in shop A. Intersection, difference and union then answer each question in one expression.

Quick Quiz

1. What does len({"a", "b", "a", "c", "b"}) return?

2. Which line creates an empty set?

3. With a = {1, 2, 3} and b = {2, 3, 4}, what is a - b?

4. What is the difference between discard(x) and remove(x)?

Learn Python with a mentor

Free lessons get you started. Our Python Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call