Step 1 of 7 · Reading · ~4 min
Learn
Dictionaries and Sets
Dictionary Techniques
By the end of this lesson you can count and group with Counter and defaultdict, merge dictionaries knowing which side wins, and spot the places where these tools quietly do something you did not ask for.
The d[k] = d.get(k, 0) + 1 loop from Dictionary Fundamentals is the manual version of counting. The standard library packages that loop, and the grouping loop that goes with it.
Counter: a dict that counts
collections.Counter is a dict subclass. Give it any iterable and it counts the items:
A missing key reads as 0 and is not inserted, so c[k] += n works on the first sight of a key, and n can be negative. most_common(n) returns the n biggest (key, count) pairs. Equal counts come out in first-seen order:
Print dict(c) or loop over c.items(), not the raw Counter.
Counter + keeps only positives
+ adds counts per key and then drops every key whose total is zero or negative. update adds the same way but keeps what it computes:
When counts can be zero or negative (refunds, stock sent out), accumulate with c[k] += n, never with + or sum() of Counters.
defaultdict: a dict that builds missing values
defaultdict(factory) calls factory() with no arguments when you read a key it lacks, stores the result under that key, and returns it. list and int (int() is 0) are the usual factories:
Any class callable with no arguments works as the factory, so defaultdict(Counter) gives each key its own Counter and table[a][b] += 1 counts in two levels.
The trap: a plain read inserts. get and in do not:
An if d[k]: meant as a question has just added k.
setdefault, merging, inverting
On a plain dict, d.setdefault(k, v) returns d[k] if present, otherwise stores v and returns it, so groups.setdefault(team, []).append(ticket_id) is the grouping loop without an import.
{**a, **b} builds a new dict and the later one wins a clash; a.update(b) does it in place. The a | b operator is Python 3.9 and raises TypeError on the 3.8 grader. A merge replaces values, it does not add them: to add, merge Counters.
Inverting collides the same way. {v: k for k, v in s.items()} on {"ann": "ops", "bo": "web", "cy": "ops"} gives {'ops': 'cy', 'web': 'bo'} and ann is lost. Group instead (inv[v].append(k) on a defaultdict(list)) to keep everyone.
Common mistakes
- Combining Counters with
+orsum()when counts can be zero or negative. A key totalling0vanishes, and if every total is non-positive the result is empty, somost_common(1)[0]raisesIndexError. - Probing a
defaultdictwithd[k]. The key is inserted, so a laterlen(d)counts keys that were only asked about. dict.fromkeys(keys, [])stores one list under every key: afterf["a"].append(1),fis{'a': [1], 'b': [1]}, the aliasing from List Basics. Use{k: [] for k in keys}.
Your exercise
Summarise a warehouse movement log where quantities can be negative: per-warehouse figures, then the top item overall. A warehouse whose total is zero is still reported, and ties for top go to the item seen first.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…