Skip to content
Lesson 6 of 12

Step 1 of 7 · Reading · ~4 min

Learn

Dictionaries and Sets

Sets and Operations

You will be able to compare groups of items with set algebra instead of nested loops, de-duplicate with or without keeping the order, and avoid the traps in combining more than two sets.

In Dictionary Fundamentals you saw that dict keys must be hashable. Set members follow the same rule for the same reason: a set is an unordered collection of unique, hashable items, much like a dict that keeps only keys.

Building sets

python

{} is an empty dict, so an empty set is always set(). Converting a list to a set drops duplicates but also drops the order; dict.fromkeys de-duplicates and keeps first-seen order. The last line is a set comprehension, a comprehension in braces with no colon.

add(x) inserts, discard(x) removes quietly, and remove(x) raises KeyError: 9 if 9 is absent. Tuples work as members, so {(1, 2), (2, 1)} holds two pairs.

A set has no order worth printing, and string hashing is randomised per process: the same set of names can print differently on the next run. Use sorted(s) whenever the output matters.

The algebra

Each operation has an operator form and a method form.

python

The methods union, intersection, difference and symmetric_difference take any iterable, while the operators need a set on both sides:

python

Comparisons ask a yes/no question: {1, 2} <= x is True (subset), x <= x is True but x < x is False (a proper subset must be strictly smaller), x >= {1, 2} is the superset test, and {1, 2}.isdisjoint({7}) is True because nothing is shared.

Chaining and the parity trap

Operators chain left to right, so a - b - c removes b, then c. ^ is the surprising one. In ^, an item survives if it is in an odd number of the sets, not if it is in exactly one:

python

Here 1 and 5 sit in one set, but 3 sits in all three and still appears; 2 and 4 sit in two sets and vanish. A chain of ^ therefore answers "odd count", and an "exactly one" or "exactly two" question needs extra set algebra on top of it.

Why in is fast, and sets of sets

x in some_list compares item after item. x in some_set hashes x and jumps to its slot, so the cost barely grows with size. Build the set once, then test against it many times.

A set cannot hold another set, because sets are mutable and unhashable ({{1, 2}} raises TypeError: unhashable type: 'set'). A frozenset is an immutable set, so it can be a member or a dict key, and {frozenset({1, 2}), frozenset({2, 1})} has length 1.

Common mistakes

  • Writing {} for an empty set. .add then fails with AttributeError: 'dict' object has no attribute 'add'.
  • Printing a set, or joining it, without sorted. The names come out in a different order from run to run, so an exact-output check fails intermittently.
  • Reading a ^ b ^ c as "exactly one". Anyone on all three lists is still in the result.
  • Swapping the operands of -. x - y is {1, 2} and y - x is {5, 6}.

Your exercise

You get three lists of guests and must report five groups of them, each printed sorted. The starter reads the lists and handles printing; fill in the five set expressions. The most likely mistake is counting guests on all three lists as "exactly one" or "exactly two".

Up nextDefining FunctionsFunctions

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…