Collections: Counter, defaultdict, namedtuple, OrderedDict
In short: collections ships four small upgrades on dict and tuple, each
solving one pattern you'd otherwise write by hand. Counter tallies hashable things
and returns 0 instead of raising on a key you never saw. defaultdict fills in a
missing key's starting value automatically, so groups[key].append(x) just works on
the first hit. namedtuple gives a plain tuple's fields real names instead of magic
indices, and OrderedDict is a dict that remembers arrival order and can move a key
back to the front on demand. Reach for one of these before you hand-roll the same
three lines again.

Count votes in a poll
Four candidates, one vote per line. Counting by hand with a plain dict fails the moment a name shows up for the first time:
votes = ["A", "B", "A", "C", "A", "B"]
counts = {}
for v in votes:
counts[v] += 1
print(counts)Counter is a dict built for exactly this — every key starts at 0, so += 1 just
works, and it comes with .most_common() for free:
Counter is a dict (isinstance(tally, dict) is True), so every dict method
still works. .most_common() and the arithmetic (Counter(...) + Counter(...),
-, &, |) are what it adds.
Roll call by class
A school's enrolment list pairs each student with their class. Grouping students by class is the same missing-key problem, one level up:
KeyErrorRun it and read which class crashes first. Then swap the plain dict for a defaultdict(list).
defaultdict(list) takes a factory — a function called with no arguments to
build the missing value. list makes [], int makes 0, and you can pass your
own function too. Once a roll is grouped, give each row real field names instead of
a bare tuple:
Keep a recent-orders log in order
A kitchen screen shows orders in the sequence they arrived, and "bump" moves a
reopened order back to the front of the queue. A plain dict already remembers
insertion order since Python 3.7 — but it has no way to change an item's
position without deleting and re-adding it. OrderedDict adds exactly that:
The one-word difference from a plain dict that trips people up is equality:
from collections import OrderedDict
a = OrderedDict([("x", 1), ("y", 2)])
b = OrderedDict([("y", 2), ("x", 1)])
print(a == b)Quick practice
from collections import Counter
bag = Counter("mississippi")
print(bag.most_common(1))Run it and see every total stuck at 0. Fix the line that's supposed to add up the prices.
from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(3, 4)
print(p[0] + p.y)🎯 Your turn
Write word_tally(words): count how many times each word appears, and return the
top 3 most common as a list of [word, count] pairs, most frequent first (ties
keep the order the words first appeared in).
word_tally(["a", "b", "a", "c", "b", "a"])→[["a", 3], ["b", 2], ["c", 1]]word_tally([])→[]
Hint: Counter(words).most_common(3) returns a list of (word, count) tuples —
turn each one into a list with [list(pair) for pair in ...].
Press ▶ Run and hit ✓ Check. ✅
