AmouAI Hub/Courses/Programming Fundamentals/Day 9
Dictionaries & Sets
Key-value modelling, membership testing that stays fast as data grows, and a framework for choosing the right structure.
By the end of today you can
- Build and read a dictionary, and reach for
.get()when a key may be missing - Count and group with a dictionary — the two patterns you will use most
- Explain hashing well enough to predict what can and cannot be a key
- Say why
inon a dict stays fast whileinon a list does not - Use a set for membership, deduplication and set arithmetic
- Choose between list, dict and set from the question being asked
- Iterate a dict correctly with
.items() - Recognise when nesting dictionaries has become a class waiting to happen
▶Today's videos
Watch each video, then work the matching sections below. Watching alone will not do it.
.get() and when a KeyError is the right answer · the counting pattern · the grouping pattern · iterating with .items() · Counter and defaultdict, after you have written them by hand.1Key-value modelling
When position is the wrong way to find things.
A list answers "what is at position 3?". A dictionary answers "what is associated with this key?" — which is what you actually want far more often.
ages = {"Amin": 34, "Ada": 36, "Grace": 45}
print(ages["Amin"])
ages["Alan"] = 41 # add
ages["Amin"] = 35 # update — same syntax
print("Ada" in ages)
print(len(ages))
print(ages.get("Nobody", 0)) # a default instead of a crashages["Nobody"] raises KeyError. Use .get(key, default) when a missing key is normal, and let the KeyError happen when a missing key means something has genuinely gone wrong. Silencing every error is not robustness — it is hiding.
Iterating properly
for name in ages: # keys, by default
print(name)
for name, age in ages.items(): # both — use this one
print(f"{name} is {age}").items() gives you a tuple per entry, which you unpack exactly as you learned yesterday. Since Python 3.7 dictionaries keep insertion order, so iteration is predictable — but do not confuse that with being sorted.
2Counting and grouping
Two patterns that cover most real dictionary work.
counts.get(ch, 0) + 1 is the whole counting pattern. The .get supplies zero the first time a key is seen, so there is no special case for "first time".
Grouping
words = ["apple", "avocado", "banana", "blueberry", "cherry"]
by_letter = {}
for word in words:
first = word[0]
if first not in by_letter:
by_letter[first] = []
by_letter[first].append(word)
for letter, group in by_letter.items():
print(letter, group)collections.Counter does the counting pattern and collections.defaultdict(list) does the grouping one. Write them by hand today so you know what they do, then use the built-ins forever after. You meet them properly tomorrow, when modules arrive.
3Hashing, intuitively
Why a dictionary does not slow down as it grows.
Finding a name in a list means checking items one at a time — a thousand items, up to a thousand comparisons. A dictionary does something different: it computes where the key should live.
A hash function turns a key into a number; the number picks a bucket. Lookup runs the same function and goes straight to that bucket — it does not scan. That is why a dictionary with a million entries is about as fast as one with ten.
Which explains the rules about keys
| Can it be a key? | Type | Why |
|---|---|---|
| Yes | str, int, float, bool, tuple | Immutable — the hash never changes |
| No | list, dict, set | Mutable — the hash would change and the key would be lost |
Yesterday a tuple looked like a list with a restriction. Today the restriction is the feature: because a tuple cannot change, its hash is stable, so it can be a key. locations[(3, 4)] = "treasure" works; a list there raises TypeError: unhashable type: 'list'.
The cost, measured
x in some_list is the blue line — the work grows with the data. x in some_dict is the green line — flat. For a handful of items the difference is irrelevant. For fifty thousand it is the difference between instant and unusable. You will make this argument properly with Big-O on Day 11.
4Sets
A dictionary with the values thrown away — which is more useful than it sounds.
seen = {3, 1, 4, 1, 5, 9, 2, 6, 5}
print(seen) # duplicates gone, order not guaranteed
tags = set() # NOT {} — that is an empty dict
tags.add("python")
tags.add("python") # no effect
print(len(tags))
a = {1, 2, 3, 4}
b = {3, 4, 5}
print(a & b) # in both
print(a | b) # in either
print(a - b) # in a only
print(a ^ b) # in exactly one{} is an empty dict, not an empty setThis catches everyone once. Use set() for an empty set. There is no shorter spelling, because {} was taken by dictionaries first.
The three things sets are for
- Deduplication —
list(set(items))removes duplicates in one step (and loses order). - Membership —
if word in stopwords:wherestopwordsis a set, not a list. - Set arithmetic — "which users are in both groups?" is
a & b, not a nested loop.
5Choosing the structure
The question you are asking picks the answer.
| If the question is… | Reach for | Because |
|---|---|---|
| "What is at position n?" | list | Order and position are the point |
| "What is associated with k?" | dict | Direct lookup by key |
| "Have I seen x before?" | set | Fast membership, no duplicates |
| "How many of each?" | dict | The counting pattern |
| "Which are in both?" | set | a & b |
| "One record, several fields" | tuple | Fixed shape, immutable, hashable |
When a dict has outgrown itself
# this works, and it is a warning sign
book = {
"title": "Think Python",
"author": "Downey",
"year": 2015,
"tags": {"python", "beginner"},
}
# every access is a string you can typo, with no help from the editor
print(book["athor"]) # KeyError, at runtime, maybe in productionA dictionary with a fixed set of keys, copied around your program, is a class waiting to happen. When every record has the same shape and you keep writing functions that take that dict as their first argument, you have discovered objects without naming them. Day 12 names them.
>_Python playground
A real Python interpreter running inside your browser. Nothing is installed, nothing is uploaded, nothing can break.
input(), comma separated →
✓Exercise set
Checked automatically the moment you submit. Work top to bottom — each one assumes the last. Your answers are saved in this browser.
Day 10 — Files, Modules & Mini-Project 2
Programs that outlive their own run: files, modules, and Mini-Project 2.