097. Set Comprehensions
Build sets concisely to collect unique transformed values
097. Set Comprehensions
Rohan collects snapshots every 5 seconds for an hour. Each snapshot has a list of running processes. He wants to know: which unique process names appeared across ALL snapshots?
Without set comprehensions:
seen = set()
for snap in snapshots:
for proc in snap["processes"]:
seen.add(proc["name"].lower())With a set comprehension:
seen = {
proc["name"].lower()
for snap in snapshots
for proc in snap["processes"]
}One expression. No .add() calls. Duplicates are discarded automatically.
He also needs the unique set of PID owners (the user each process runs as):
owners = {proc["username"] for proc in snapshot["processes"] if proc["username"]}And the set of distinct RSS sizes rounded to the nearest 100 MB (useful for bucketing):
buckets = {(proc["rss_mb"] // 100) * 100 for proc in snapshot["processes"]}Set vs list comprehension: Use
{...}for uniqueness,[...]when order matters or duplicates are meaningful. A set lookupx in sis O(1); a list lookup is O(n). For 10,000 processes, thatβs the difference between microseconds and milliseconds.
π‘ Fun fact: Python sets are implemented as hash tables β the same data structure used in dictionaries. The set type was added in Python 2.4 (2004), and set comprehension syntax {x for x in ...} was introduced in Python 2.7 / 3.0. Before that, you had to write set(x for x in ...).
β οΈ Watch out: The most common beginner mistake is confusing {} (empty dict) with set() (empty set). Writing s = {} creates an empty dict, not a set. To create an empty set, always write set().
π€ Think about it: If sets are unordered and discard duplicates, what happens when you convert a list with duplicates to a set and then back to a list? Can you ever rely on the resulting order?
Learning objectives
- Create sets with set comprehensions using curly braces
- Add filter conditions to set comprehensions
- Understand that set comprehensions automatically deduplicate
- Choose set vs list based on whether uniqueness or order is needed
Key concepts
- set comprehension
- deduplication
- unique values
- hashable
Try it
Concept detail
Set comprehension syntax: {expression for variable in iterable [if condition]}
Examples: {word.lower() for word in words} β unique lowercased words {x for x in items if x > 0} β unique positive values {email.split(β@β)[1] for email in emails} β unique email domains
The result is always a set β duplicates are automatically discarded. Unlike list comprehensions, set comprehensions have no guaranteed order.
When to use a set vs list: Set β you need uniqueness, fast membership testing (O(1)) List β you need order, duplicates are meaningful, or you need indexing
{x for x in items} is equivalent to set(x for x in items) but the comprehension form is preferred for readability.
Cannot store unhashable types in a set: {[1, 2], [3, 4]} # TypeError β lists are not hashable {(1, 2), (3, 4)} # OK β tuples are hashable
Nested set comprehension (flat): {ch for word in words for ch in word if ch.isalpha()} β all unique letters across all words
Solution
def unique_domains(emails):
return {email.split("@")[1] for email in emails}
def unique_lengths(words):
return {len(word) for word in words}
def vowels_in(text):
return {ch for ch in text.lower() if ch in "aeiou"}Tests
def test_unique_domains():
emails = ["[email protected]", "[email protected]", "[email protected]"]
result = unique_domains(emails)
assert result == {"gmail.com", "yahoo.com"}
def test_unique_domains_one():
emails = ["[email protected]", "[email protected]"]
assert unique_domains(emails) == {"same.org"}
def test_unique_lengths():
result = unique_lengths(["cat", "dog", "elephant", "ox"])
assert result == {3, 8, 2}
def test_vowels_in():
result = vowels_in("Hello World")
assert result == {"e", "o"}
def test_vowels_empty():
result = vowels_in("rhythm")
assert result == set()