Sets
Many problems come down to a bag of things with no order and no repeats. The distinct words in a book, the student numbers enrolled in a course, the users who have followed one account on a social network, and the IP addresses that visited a web page in the last hour are all collections of this kind: the order they are listed in carries no meaning, and listing the same item twice adds nothing. The data structure for such a collection is the set.
Sets are a basic language of mathematics as well, and the notation introduced here recurs in logic, probability, and discrete mathematics. These notes cover the set, its operations and notation in math, and the set type that Python provides, which supports all of the same operations and runs them quickly.
What is a set?
Section titled “What is a set?”A set is an unordered collection of distinct elements. Two sets are equal when they contain exactly the same elements; the order in which they are listed and any apparent repetition do not matter. For instance, , , and all name the same set.
An element may belong to a set or not, and nothing else is said about its position. Compare this with a list, in which each element has a specific index, or with a priority queue, in which each element has a priority.
A set may have any number of elements, including none. The empty set, written or , has no elements. The elements themselves may be numbers, strings, or whole other sets; what matters is only that each element either is or is not in the set.
Set notation
Section titled “Set notation”Three symbols cover most of what one writes about a single set:
- means that belongs to the set . One reads it ” is in ” or ” is an element of ”. Its negation, , means that is not an element of .
- is the number of elements in , called the cardinality of . The empty set has .
- Set literals are written with braces, as .
A few sets are so common that they have reserved names: for the natural numbers , for the integers, for the rationals, and for the real numbers.
Set-builder notation
Section titled “Set-builder notation”Listing every element is only practical when the set is small. For larger sets, set-builder notation describes the set by a rule its elements must satisfy. Two forms recur:
- is the set of elements of for which the condition holds. Read it “the set of in such that of ”. Some books write a vertical bar in place of the colon, as ; the meaning is the same.
- is the set of values that takes on .
For example, , and .
Equality and subsets
Section titled “Equality and subsets”A set is a subset of a set , written , when every element of is also an element of . Equivalently, implies for every . The empty set is a subset of every set, and every set is a subset of itself.
Two sets are equal exactly when each is a subset of the other: iff and . This two-sided check is the usual way to prove that two sets are equal in the general case, when they are not given by listing their elements.
If and , then is a proper subset of , written . The symbols and reverse the direction: means the same as .
Combining sets
Section titled “Combining sets”Three operations build new sets from old ones:
- Union , the elements in at least one of or .
- Intersection , the elements in both.
- Difference , the elements in but not in . Some books write this as .
Union and intersection are commutative and associative, so , and , and the same for . Difference is neither: in general . Two sets and are called disjoint when .
A Venn diagram pictures these operations as overlapping regions. The union is the whole shaded area under either circle; the intersection is the lens where the circles overlap; the difference is the part of ‘s circle outside ‘s.
Inclusion and exclusion
Section titled “Inclusion and exclusion”Counting the elements of a union must avoid counting the overlap twice. For two sets,
For three sets, each pairwise intersection is subtracted, and the triple intersection is added back:
This pattern of alternating signs is the inclusion–exclusion principle, which generalizes to any number of sets.
Cartesian product and power set
Section titled “Cartesian product and power set”Two further constructions appear often. The Cartesian product of and is the set of ordered pairs with first entry from and second from :
Its cardinality is . The -fold product holds all tuples of length with entries from .
The power set of , written or , is the set of all subsets of :
A finite set with elements has subsets: for each element, a subset either includes it or does not, and the choices for different elements are independent. For example, , with four elements, and .
Sets in Python
Section titled “Sets in Python”Python’s built-in set type carries all of the operations above. A set literal lists its elements in braces, and the set constructor turns any iterable into a set, dropping duplicates:
primes = {2, 3, 5, 7, 11}letters = set("mississippi") # {'m', 'i', 's', 'p'}empty = set() # not {} — that is an empty dictThe one surprise is that {} is an empty dict, not an empty set; use set() for the empty set.
Membership and cardinality mirror the mathematical notation:
3 in primes # True4 in primes # Falselen(primes) # 5The three set operations are available both as operators and as named methods:
| Math | Operator | Method |
|---|---|---|
| `a | b` | |
a & b | a.intersection(b) | |
a - b | a.difference(b) | |
a ^ b | a.symmetric_difference(b) | |
a <= b | a.issubset(b) | |
a < b | — |
The last row is the symmetric difference , the elements in one of or but not both.
Sets are mutable, with methods to add and remove elements:
s = {1, 2, 3}s.add(4) # s is now {1, 2, 3, 4}s.discard(2) # s is now {1, 3, 4}; discard of a missing element does nothings.remove(5) # KeyError: 5 is not in sMutating variants of the binary operators update a set in place: a |= b, a &= b, a -= b, and a ^= b.
Hashable elements
Section titled “Hashable elements”Not every value may be an element of a set. Python requires that each element be hashable: that it have a stable value under hashing that will not change for the lifetime of the object. Numbers, strings, and tuples of hashable things are all fine. Lists and other sets are not, because their contents can change after they are stored. A tuple of coordinates may belong to a set, but a list of them may not:
{(0, 0), (1, 2), (3, 4)} # a set of three points{[0, 0], [1, 2]} # TypeError: unhashable type: 'list'To hold a set of sets, use Python’s frozenset, an immutable version of set that is hashable.
Set comprehensions
Section titled “Set comprehensions”Set-builder notation translates almost word for word into a set comprehension:
# {n in range(10) : n is even}evens = {n for n in range(10) if n % 2 == 0}
# {n^2 : n in {1, 2, 3, 4}}squares = {n * n for n in {1, 2, 3, 4}}
# the set of letters that appear in a stringletters = {c for c in "hello world" if c.isalpha()}The syntax matches a list comprehension, with braces in place of brackets. The resulting set has no duplicates and no particular order.
How fast are set operations?
Section titled “How fast are set operations?”Both x in s and s.add(x) run in near-constant time on average, independent of how many items s holds. That is why a set is the right data structure for membership tests on large collections, and why dedup through set(items) is a one-line solution. These speeds come from the way Python stores its sets, which is covered in the notes on hash tables.
An example: document similarity
Section titled “An example: document similarity”A short application brings the pieces together. Given two short texts, how similar are they? One simple measure of similarity between any two sets and is the Jaccard similarity,
which is for disjoint sets and for equal nonempty sets. Applied to the set of distinct words in each of two documents, Jaccard similarity gives a quick, order-independent score for how much vocabulary two texts share. It is used in search engines to spot near-duplicate web pages, and in plagiarism detectors to flag passages worth a second look.
A Python implementation is short:
def words(text): return {word.lower() for word in text.split()}
def jaccard(a, b): return len(a & b) / len(a | b)
doc1 = "the quick brown fox jumps over the lazy dog"doc2 = "the quick brown dog jumps over a sleeping fox"
jaccard(words(doc1), words(doc2)) # 0.7Seven words are shared (the, quick, brown, fox, jumps, over, dog), and the union holds ten distinct words, so . The score ignores word order, which is both a strength (small rearrangements do not fool it) and a weakness (two documents built from the same vocabulary can score high even if they say opposite things).
A natural refinement is to split the text into overlapping k-grams of consecutive words, then compute the Jaccard similarity of the resulting sets of k-grams. The order of words then matters within each k-gram, and small reorderings no longer give full credit.
Source material for these notes
Section titled “Source material for these notes”The treatment of set notation, equality, subsets, and the operations , , and follows Rosen, Discrete Mathematics and Its Applications, chapter 2. The inclusion–exclusion principle and its proof by induction appear in the same book, chapter 8. The Jaccard similarity was introduced by Paul Jaccard in 1912 for comparing the floras of two regions.
The text, the sections on sets in Python, the document-similarity example, the figure, and the practice problems were drafted by Claude (Anthropic) at Balkcom’s direction, following the sources above, and then edited by Balkcom. The Python material can also be found in the Python documentation for set, and the use of the Jaccard similarity to compare documents in Leskovec, Rajaraman, and Ullman, Mining of Massive Datasets, chapter 3.
Further reading
Section titled “Further reading”set— Python’s built-in set typefrozenset— an immutable set that may itself be a set element- Set comprehensions in the Python tutorial
Practice problems
Section titled “Practice problems”Try these on your own before checking the solutions.
Problem 1: Set-builder
Section titled “Problem 1: Set-builder”Write out each of the following sets by listing its elements.
(Solution)
Problem 2: Operations by hand
Section titled “Problem 2: Operations by hand”Let , , and . Compute each of the following.
(Solution)
Problem 3: Inclusion and exclusion
Section titled “Problem 3: Inclusion and exclusion”In a class of 60 students, 35 take mathematics, 28 take computer science, and 15 take both. How many take at least one of the two? How many take neither?
(Solution)
Problem 4: Subsets of a small set
Section titled “Problem 4: Subsets of a small set”List every subset of . How many are there, and how many of them contain ?
(Solution)
Problem 5: Prove a set identity
Section titled “Problem 5: Prove a set identity”Prove that for any sets , , and , by showing that each side is a subset of the other.
Note: this problem is for practice only. Proof problems like this one will not be tested in CS 10.
(Solution)
Problem 6: Common letters
Section titled “Problem 6: Common letters”Write a Python function common_letters(s, t) that returns the set of lowercase letters that appear in both of two strings s and t, ignoring case and ignoring any non-letter characters. For example, common_letters("Hello", "World!") returns {'l', 'o'}.
(Solution)
Problem 7: Jaccard by hand
Section titled “Problem 7: Jaccard by hand”Compute the Jaccard similarity of the word sets of the two sentences “a rose is a rose” and “roses are red, roses are blue”, treating each distinct word as an element.
(Solution)