Skip to content

05-03: Sets

A set is an unordered collection of unique, hashable elements. Duplicates are automatically removed.


Creating Sets

# With curly braces
s = {1, 2, 3, 4, 5}

# With set() constructor
s2 = set()                    # empty set
s3 = set([1, 2, 2, 3, 3, 3]) # from list — removes duplicates
print(s3)   # {1, 2, 3}

# From string — unique characters
s4 = set("hello")
print(s4)   # {'h', 'e', 'l', 'o'}  (only unique chars)

# Duplicates are removed automatically
s5 = {1, 2, 2, 3, 3, 3, 4}
print(s5)   # {1, 2, 3, 4}

# IMPORTANT: {} creates empty DICT not empty set!
empty_dict = {}          # dict
empty_set  = set()       # set
print(type(empty_dict))  # <class 'dict'>
print(type(empty_set))   # <class 'set'>

Key Properties

  • Unordered — no guaranteed order when printed
  • Unique — no duplicate elements
  • Mutable — can add/remove elements
  • Unhashable items not allowed — can't contain lists or other sets
# Sets cannot contain unhashable types
valid   = {1, 2.5, "hello", (1, 2), True}   # OK
invalid = {[1, 2]}   # TypeError: unhashable type: 'list'

Membership Testing

Sets excel at fast membership testing (O(1) vs O(n) for lists):

allowed = {"admin", "editor", "viewer"}

user_role = "editor"
if user_role in allowed:
    print("Access granted")

print("admin" in allowed)    # True
print("guest" in allowed)    # False
print("guest" not in allowed) # True

Adding Elements

s = {1, 2, 3}

# add() — add one element (no-op if already present)
s.add(4)
print(s)    # {1, 2, 3, 4}

s.add(2)    # no-op — 2 already in set
print(s)    # {1, 2, 3, 4}

# update() — add multiple elements from any iterable
s.update([5, 6, 7])
print(s)    # {1, 2, 3, 4, 5, 6, 7}

s.update("abc")   # adds 'a', 'b', 'c'
s.update({10, 11}, [12, 13])   # multiple iterables

Removing Elements

s = {1, 2, 3, 4, 5}

# remove() — raises KeyError if not found
s.remove(3)
print(s)    # {1, 2, 4, 5}
s.remove(9)  # KeyError!

# discard() — no error if not found (safer)
s.discard(2)
print(s)    # {1, 4, 5}
s.discard(99)  # no error

# pop() — removes and returns an arbitrary element
item = s.pop()
print(item)  # some element (order unpredictable)

# clear() — remove all elements
s.clear()
print(s)    # set()

Set Operations

Union — all unique elements from both sets

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

print(a | b)           # {1, 2, 3, 4, 5, 6}  — operator
print(a.union(b))      # {1, 2, 3, 4, 5, 6}  — method
print(a.union(b, {7, 8}))  # {1, 2, 3, 4, 5, 6, 7, 8}  — multiple sets

Intersection — elements in both sets

print(a & b)              # {3, 4}
print(a.intersection(b))  # {3, 4}

Difference — elements in a but not b

print(a - b)            # {1, 2}
print(a.difference(b))  # {1, 2}
print(b - a)            # {5, 6}

Symmetric Difference — elements in either but not both

print(a ^ b)                       # {1, 2, 5, 6}
print(a.symmetric_difference(b))   # {1, 2, 5, 6}

Subset and Superset

x = {1, 2}
y = {1, 2, 3, 4}

print(x.issubset(y))     # True  — all of x is in y
print(x <= y)            # True  — subset operator
print(x < y)             # True  — proper subset (x != y)

print(y.issuperset(x))   # True  — y contains all of x
print(y >= x)            # True
print(y > x)             # True  — proper superset

print(x.isdisjoint({3, 4}))  # True — no common elements
print(x.isdisjoint({2, 3}))  # False — 2 is common

In-Place Set Operations

a = {1, 2, 3}
b = {3, 4, 5}

a |= b           # a = a | b  (union)
print(a)         # {1, 2, 3, 4, 5}

a &= {2, 3, 4}   # a = a & {2,3,4}  (intersection)
print(a)         # {2, 3, 4}

a -= {3}         # a = a - {3}  (difference)
print(a)         # {2, 4}

a ^= {1, 2}      # a = a ^ {1,2}  (symmetric diff)
print(a)         # {1, 4}

Set Comprehensions

# All unique characters (no spaces) in a sentence
text = "hello world python programming"
unique_chars = {c for c in text if c != " "}
print(sorted(unique_chars))

# Squares of even numbers
even_squares = {x**2 for x in range(10) if x % 2 == 0}
print(even_squares)   # {0, 4, 16, 36, 64}

Practical Use Cases

Remove duplicates from a list (preserving order)

original = [1, 3, 2, 1, 4, 3, 5]
# Simple but loses order:
unique = list(set(original))

# Preserving order:
seen = set()
unique_ordered = []
for item in original:
    if item not in seen:
        unique_ordered.append(item)
        seen.add(item)
print(unique_ordered)   # [1, 3, 2, 4, 5]

Fast lookup

# Using a set for O(1) lookup
stop_words = {"the", "a", "an", "is", "are", "was", "were", "in", "on"}

text = "the quick brown fox is in the forest"
filtered = [word for word in text.split() if word not in stop_words]
print(filtered)   # ['quick', 'brown', 'fox', 'forest']

Finding common/unique items

students_A = {"Alice", "Bob", "Charlie", "Dave"}
students_B = {"Bob", "Dave", "Eve", "Frank"}

# Students in both classes
both     = students_A & students_B
print("Both:", both)      # {'Bob', 'Dave'}

# Only in class A
only_A   = students_A - students_B
print("Only A:", only_A)  # {'Alice', 'Charlie'}

# Either class (union)
either   = students_A | students_B
print("All:", either)

# Exactly one class
one_only = students_A ^ students_B
print("One only:", one_only)  # {'Alice', 'Charlie', 'Eve', 'Frank'}

Iteration

s = {3, 1, 4, 1, 5, 9, 2, 6}

# Iterate (order not guaranteed)
for item in s:
    print(item, end=" ")

# Sort for deterministic output
for item in sorted(s):
    print(item, end=" ")
# 1 2 3 4 5 6 9

print(len(s))   # 7 (duplicates removed)

frozenset — Immutable Set

A frozenset is an immutable version of a set — hashable, so it can be used as a dictionary key or as an element of another set:

fs = frozenset([1, 2, 3, 4])
print(fs)          # frozenset({1, 2, 3, 4})

# Can be used as dict key
config = {frozenset(["read", "write"]): "admin"}

# Can be element of set
s = {frozenset({1, 2}), frozenset({3, 4})}

Complete Method Reference

Method Operator Description
add(x) Add element
discard(x) Remove if present (no error)
remove(x) Remove (KeyError if absent)
pop() Remove & return arbitrary element
clear() Remove all elements
union(s) \| All elements from both
intersection(s) & Common elements
difference(s) - In self, not in s
symmetric_difference(s) ^ In one or the other, not both
issubset(s) <= All of self in s
issuperset(s) >= All of s in self
isdisjoint(s) No common elements
update(s) \|= Add all from s
intersection_update(s) &= Keep only common elements
difference_update(s) -= Remove elements in s
symmetric_difference_update(s) ^= Keep only non-common

Practice Problems

# 1. Count unique words in a sentence
sentence = "to be or not to be that is the question"
unique_words = set(sentence.split())
print(f"Unique words: {len(unique_words)}")

# 2. Intersection of multiple sets
lists = [[1,2,3,4], [2,3,4,5], [3,4,5,6]]
common = set(lists[0])
for lst in lists[1:]:
    common &= set(lst)
print(common)   # {3, 4}

# 3. Check if two strings are anagrams
def are_anagrams(s1, s2):
    return set(s1.lower()) == set(s2.lower()) and \
           sorted(s1.lower()) == sorted(s2.lower())

print(are_anagrams("listen", "silent"))   # True
print(are_anagrams("hello", "world"))     # False

# 4. Power set (all subsets)
def power_set(s):
    result = [set()]
    for item in s:
        result += [existing | {item} for existing in result]
    return result

print(power_set({1, 2, 3}))

Exercises: 05-03: Exercises — Sets


⬅️ Previous: 05-02: Tuples ➡️ Next: 05-04: Dictionaries