Dictionaries & Sets

0/5 in this phase0/54 across the roadmap

📖 Concept

Dictionaries (dict) are Python's built-in hash map — key-value pairs with O(1) average lookup, insertion, and deletion. They are the backbone of Python programming, used everywhere from function kwargs to JSON data to object attributes.

Sets are unordered collections of unique elements, backed by hash tables. They provide O(1) membership testing and support mathematical set operations (union, intersection, difference).

Dictionary key requirements: Keys must be hashable (immutable): strings, numbers, tuples (of hashable elements), frozensets. Lists, dicts, and sets cannot be dictionary keys.

Dictionary ordering: Since Python 3.7, dictionaries maintain insertion order (this was an implementation detail in CPython 3.6, made part of the language spec in 3.7).

Dict comprehensions:

{key_expr: value_expr for item in iterable if condition}

Useful dict methods:

  • .get(key, default) — return default if key missing (instead of KeyError)
  • .setdefault(key, default) — set and return default if key missing
  • .update(other) — merge another dict (or key-value pairs)
  • .pop(key, default) — remove and return value
  • |= merge operator (Python 3.9+) — dict1 |= dict2

Set operations:

Operation Method Operator Result
Union a.union(b) a | b All elements from both
Intersection a.intersection(b) a & b Common elements
Difference a.difference(b) a - b Elements in a but not b
Symmetric diff a.symmetric_difference(b) a ^ b Elements in either, not both

💻 Code Example

codeTap to expand ⛶
1# ============================================================
2# Dictionary creation
3# ============================================================
4# Literal syntax
5user = {"name": "Alice", "age": 30, "city": "NYC"}
6
7# From pairs
8pairs = [("a", 1), ("b", 2), ("c", 3)]
9d = dict(pairs)
10
11# From kwargs
12d = dict(name="Alice", age=30)
13
14# Dict comprehension
15squares = {x: x**2 for x in range(6)}
16print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
17
18# From keys with default value
19keys = ["a", "b", "c"]
20d = dict.fromkeys(keys, 0) # {'a': 0, 'b': 0, 'c': 0}
21
22# ============================================================
23# Accessing and modifying
24# ============================================================
25user = {"name": "Alice", "age": 30}
26
27# Access
28print(user["name"]) # "Alice"
29# print(user["email"]) # KeyError!
30print(user.get("email")) # None (no error)
31print(user.get("email", "N/A")) # "N/A" (custom default)
32
33# Modify
34user["age"] = 31 # Update existing
35user["email"] = "a@b.com" # Add new key
36
37# Remove
38del user["email"] # Remove key (KeyError if missing)
39age = user.pop("age") # Remove and return value
40last = user.popitem() # Remove and return last inserted pair
41
42# setdefault: get or set
43cache = {}
44cache.setdefault("key", []).append(1)
45cache.setdefault("key", []).append(2)
46print(cache) # {'key': [1, 2]}
47
48# ============================================================
49# Merging dictionaries
50# ============================================================
51defaults = {"theme": "dark", "lang": "en", "font_size": 14}
52user_prefs = {"theme": "light", "font_size": 16}
53
54# Method 1: unpacking (Python 3.5+)
55config = {**defaults, **user_prefs}
56print(config) # {'theme': 'light', 'lang': 'en', 'font_size': 16}
57
58# Method 2: merge operator (Python 3.9+)
59config = defaults | user_prefs # Returns new dict
60defaults |= user_prefs # In-place merge
61
62# ============================================================
63# Iterating dictionaries
64# ============================================================
65scores = {"Alice": 95, "Bob": 87, "Charlie": 92, "Diana": 88}
66
67# Keys, values, items
68for key in scores: # Iterate keys
69 print(key)
70for value in scores.values(): # Iterate values
71 print(value)
72for name, score in scores.items(): # Iterate pairs
73 print(f"{name}: {score}")
74
75# Sort by value
76for name, score in sorted(scores.items(), key=lambda x: x[1], reverse=True):
77 print(f"{name}: {score}")
78
79# ============================================================
80# defaultdict — auto-initialize missing keys
81# ============================================================
82from collections import defaultdict
83
84# Group items by category
85items = [("fruit", "apple"), ("veggie", "carrot"),
86 ("fruit", "banana"), ("veggie", "pea")]
87
88grouped = defaultdict(list)
89for category, item in items:
90 grouped[category].append(item) # No KeyError, auto-creates list
91
92print(dict(grouped))
93# {'fruit': ['apple', 'banana'], 'veggie': ['carrot', 'pea']}
94
95# Count occurrences
96word_count = defaultdict(int)
97for word in "the cat sat on the mat".split():
98 word_count[word] += 1 # Auto-initializes to 0
99
100print(dict(word_count))
101# {'the': 2, 'cat': 1, 'sat': 1, 'on': 1, 'mat': 1}
102
103# ============================================================
104# Counter — specialized dict for counting
105# ============================================================
106from collections import Counter
107
108words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
109counts = Counter(words)
110print(counts) # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
111print(counts.most_common(2)) # [('apple', 3), ('banana', 2)]
112print(counts["apple"]) # 3
113print(counts["grape"]) # 0 (no KeyError!)
114
115# Counter arithmetic
116c1 = Counter(a=3, b=1)
117c2 = Counter(a=1, b=2)
118print(c1 + c2) # Counter({'a': 4, 'b': 3})
119print(c1 - c2) # Counter({'a': 2}) (drops zero/negative)
120
121# ============================================================
122# Sets
123# ============================================================
124# Creation
125s = {1, 2, 3, 4, 5}
126empty_set = set() # NOT {} — that's an empty dict!
127from_list = set([1, 2, 2, 3, 3, 3]) # {1, 2, 3} — duplicates removed
128
129# Operations
130a = {1, 2, 3, 4, 5}
131b = {4, 5, 6, 7, 8}
132
133print(a | b) # {1, 2, 3, 4, 5, 6, 7, 8} — union
134print(a & b) # {4, 5} — intersection
135print(a - b) # {1, 2, 3} — difference
136print(a ^ b) # {1, 2, 3, 6, 7, 8} — symmetric difference
137
138# Membership (O(1) — very fast!)
139print(3 in a) # True
140
141# Subset/superset
142print({1, 2} <= a) # True — is subset
143print(a >= {1, 2}) # True — is superset
144
145# Set methods
146a.add(6) # Add element
147a.discard(10) # Remove if present (no error)
148a.remove(6) # Remove (KeyError if not present)
149
150# Practical: remove duplicates while preserving order
151items = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
152unique = list(dict.fromkeys(items)) # [3, 1, 4, 5, 9, 2, 6]
153
154# frozenset — immutable set (can be dict key or set member)
155fs = frozenset([1, 2, 3])
156d = {fs: "immutable set as key"}

🏋️ Practice Exercise

Exercises:

  1. Write a function that counts word frequencies in a text and returns the top N most common words. Use both Counter and a manual defaultdict approach.

  2. Given two lists of student IDs, find: students in both lists, students in only the first list, students in either list but not both. Use set operations.

  3. Implement a function deep_merge(dict1, dict2) that recursively merges nested dictionaries (unlike |= which overwrites nested dicts).

  4. Create an inverted index: given a dict of {document_id: [words]}, produce {word: [document_ids]} using defaultdict.

  5. Write a group_by(items, key_func) function that groups a list of items by the result of key_func, returning a dict of lists. Use defaultdict.

  6. Implement LRU (Least Recently Used) behavior using an OrderedDict: access moves an item to the end, insertion at the end, eviction from the front when capacity is exceeded.

⚠️ Common Mistakes

  • Creating an empty set with {} — this creates an empty dict, not a set. Use set() for an empty set.

  • Accessing dict keys with d[key] without checking existence. Use d.get(key, default) or key in d check to avoid KeyError.

  • Assuming dict order before Python 3.7. In Python 3.7+ dicts maintain insertion order, but if you need guaranteed ordering in older code, use collections.OrderedDict.

  • Using mutable objects (lists, dicts) as dictionary keys. Keys must be hashable. Use tuples instead of lists, frozensets instead of sets.

  • Using dict.fromkeys(keys, []) to create a dict with empty list values — all values reference the SAME list. Use {k: [] for k in keys} instead.

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for Dictionaries & Sets