Sets, and choosing the right collection

Part of the free LogicWiz Python course, Module 6: Dictionaries and sets. The examples and practice run in the app.

Meher wants two numbers by evening: how many different items sold today, and which items both she and Aarav ordered. Lists make this messy; sets make it one line each.

You'll learn to

  • Make sets, remove duplicates and test membership fast
  • Use union, intersection and difference
  • Pick between list, tuple, dict and set, and know why a list cannot be a key

Learn

A bag of unique things

A set holds each value at most once, in no fixed order: {"chai", "samosa"}.

  • set(some_list) removes duplicates.
  • add(x) adds; remove(x) deletes (KeyError if missing); discard(x) deletes quietly.
  • x in s is very fast, even for a huge set.
  • No indexes: s[0] is an error, because there is no "first".

Careful: {} is an empty dict. An empty set is set().

Removing duplicates

orders = ["chai", "samosa", "chai", "maggi", "chai"]
unique = set(orders)
print(len(unique))
print(sorted(unique))
unique.add("poha")
unique.discard("maggi")
print("maggi" in unique, "poha" in unique)
print(type(set()), type({}))

We print sorted(unique) because a set has no fixed order; printing the set itself can show the items in any order.

Union, intersection, difference

aarav = {"chai", "samosa", "maggi"}
meher = {"chai", "poha", "samosa"}
print(sorted(aarav & meher))
print(sorted(aarav | meher))
print(sorted(aarav - meher))
print(sorted(aarav ^ meher))

& both (intersection), | either (union), - in the first but not the second (difference), ^ in exactly one (symmetric difference). The method names are intersection, union, difference, symmetric_difference.

Why a list cannot be a key

Dicts and sets find things instantly by turning each key into a number called a hash. That only works if the key can never change, otherwise its hash would go stale and the item would be lost.

So keys and set items must be hashable (immutable): int, float, str, bool and tuples of those are fine. A list, dict or set is not. Need a two-part key like a seat (row, column)? Use a tuple.

Tuple key yes, list key no

seats = {}
seats[(2, 5)] = "Aarav"
print(seats[(2, 5)])
seats[[3, 1]] = "Meher"

Line 2 works. Line 4 raises TypeError: unhashable type: 'list'.

Choosing the right collection

Ordered Changeable Duplicates Find by
list [ ] yes yes yes position
tuple ( ) yes no yes position
dict {k: v} yes (insertion) yes keys unique key
set { } no yes no membership only
  • A sequence that grows (orders, a queue): list
  • A fixed record or a key made of parts: tuple
  • Look up by name or ID (price of an item): dict
  • Unique values, or "is it there?" checks: set

Three classic slips: s = {} makes a dict, so s.add(1) fails; printing a set of words can show a different order each run, so sort it before printing; and x in some_list checks every item one by one, while x in some_set jumps straight there. Inside a big loop that difference is huge.

The most-asked Python interview question: "Difference between a list, tuple, set and dict?" Answer with the table above: ordered or not, mutable or not, duplicates or not, and how you look things up. University papers also ask set operations (|, &, -) and "why is a list unhashable?"

In one line

A set keeps unique values (set() is empty, {} is a dict); & | - combine sets; keys must be hashable, so use a tuple, never a list.