The collections Module
About 18 minutes
Why this matters
Lists and dictionaries cover most needs, but a few patterns come up again and again: counting things, grouping things, and a queue you can add to at both ends. The collections module has a tool for each.
The idea
from collections import Counter, defaultdict, deque, namedtuple
Counter("banana") # Counter({'a': 3, 'n': 2, 'b': 1})
Counter("banana").most_common(1) # [('a', 3)]
groups = defaultdict(list) # a missing key starts as an empty list
groups["fruit"].append("apple") # no KeyError, no setdefault needed
queue = deque([1, 2, 3])
queue.appendleft(0) # fast at both ends
queue.popleft() # take from the front
queue.rotate(1) # [3, 0, 1, 2] -> shifts items right
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p.x, p[1] # 3 4: named AND indexable, still a tuple
Counter ties are listed in the order the items were first seen.
Try it
Count the letters of your name with Counter, then ask for the two most common ones. What happens when you look up a letter that is not there: Counter("abc")["z"]?
Your turn
Write:
top_words(text, n): thenmost common words as(word, count)tuples. Ignore capital letters and split on spaces. UseCounter.group_by_length(words): a dictionary mapping a length to the list of words with that length, in their original order:{1: ["a", "d"], 2: ["bb", "cc"]}. Usedefaultdict(list)and return an ordinarydict.rotate(items, k): a new list with the items rotatedkplaces to the right (rotate([1, 2, 3, 4, 5], 2)is[4, 5, 1, 2, 3]; a negativekrotates left). Usedeque.rotate. The original list must not change.
Recap
Countercounts,defaultdictgroups,dequeis a double-ended queue.namedtuplegives tuple fields readable names.- Import exactly what you need from
collections.
Common mistakes
- Using a
defaultdictand then reading a missing key by accident, which silently creates it. - Calling
list.pop(0)in a loop on long lists; it is slow. Adequewithpopleft()is fast. - Forgetting that
Counterreturns 0 for missing items instead of raisingKeyError.