From lesson 2-3, sorted(d.items(), key=lambda kv: kv[1]) sorts a dict's pairs by value. Each kv is a (key, value) pair, so kv[1] reaches the value half.
You are about to meet Counter, which bakes that exact sort-by-count pattern into a single method named most_common, so you rarely need to write the lambda yourself.
Counter: counting without boilerplate
The standard library exists so you do not rewrite, and re-debug, the same chores in every project. Counting things and grouping things are the two most common data chores in working Python, and this unit's collections module turns each into a line or two.
Counting things in Python for Beginners took four lines: check if the key exists, initialize it, increment. collections.Counter does it in one:
from collections import Counter votes = ["cat", "dog", "cat", "bird", "cat"] tally = Counter(votes) # Counter({'cat': 3, 'dog': 1, 'bird': 1})
A Counter is a dict (it subclasses dict, inheritance from lesson 3-4 in the wild), with extras:
tally.most_common(2)gives the top two(item, count)pairs.- Missing keys return
0instead of raisingKeyError. - Feed it any iterable: a list, a string, a generator from unit 4.
Counting letters in a word
Counter takes any iterable and tallies it. One constructor call does the counting, and one method call ranks the results.
from collections import Counter text = "mississippi" letters = Counter(text) print(letters["s"]) print(letters["z"]) print(letters.most_common(2))
Output
4 0 [('i', 4), ('s', 4)]
The middle line is the detail people miss. Looking up a letter that never appeared returns 0 instead of raising KeyError, because a Counter treats absent items as having a count of zero. That removes the if key in counts guard you would need with a plain dict.
Finding the winning vote
A Counter tallies the ballots, and most_common(1) picks out the top entry. The method always returns a list of (item, count) pairs, even when you ask for just one, so the code indexes into it and unpacks.
from collections import Counter votes = ["red", "blue", "red", "green", "red", "blue"] tally = Counter(votes) winner, count = tally.most_common(1)[0] print(winner, count)
Output
red 3tally.most_common(1) evaluates to [('red', 3)], a one-item list. Indexing with [0] gets the pair out, and winner, count = ... unpacks it into two names in one step. Forgetting the [0] is the classic slip here, and it leaves you holding a list where you expected a tuple.
defaultdict and deque
defaultdict is a dict that invents a default value for missing keys. Pass it the factory to use, like list or int:
from collections import defaultdict groups = defaultdict(list) groups["fruit"].append("apple") # no KeyError, a fresh [] appears
That kills the if key not in d: d[key] = [] dance forever, and it is the standard tool for grouping.
deque (say "deck", short for double-ended queue) stores its items so that both ends are directly reachable. As a result, appendleft and popleft take the same tiny, fixed amount of time no matter how many items the deque holds. A plain list cannot offer that: list.pop(0) must shift every remaining element one slot left, so its cost grows with the length of the list. Use a deque whenever you need a queue, like breadth-first search in the Data Structures course. (Unit 9 turns this kind of cost reasoning into a formal habit.)
Grouping words by first letter
defaultdict(list) creates an empty list automatically the first time any key is touched, which removes the "is this key here yet" check that grouping code otherwise needs.
from collections import defaultdict words = ["apple", "banana", "avocado", "cherry", "blueberry"] groups = defaultdict(list) for word in words: groups[word[0]].append(word) print(dict(groups))
Output
{'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}word[0] is the first letter, so groups[word[0]].append(word) is the entire loop body. With a plain dict that single line would need a preceding if word[0] not in groups: groups[word[0]] = []. The argument to defaultdict is the factory to call, so it is list, not list(). Wrapping the result in dict(groups) before printing just gives the plain dict display rather than the longer defaultdict(...) form.
Removing from the front of a queue
For a queue where items leave from the front, deque beats list. list.pop(0) has to shift every remaining element one slot to the left, while deque.popleft() unhooks the item directly.
| Operation | list | deque |
|---|---|---|
| append at the end | O(1) | O(1) |
| remove from the front | O(n) | O(1) |
A list stores its items in one contiguous block, so index 0 disappearing means everything behind it slides down, and that work grows with the length of the list. A deque (short for double-ended queue) is built so both ends are directly reachable, making popleft a fixed-cost operation no matter how long the queue gets. Unit 9 turns this kind of cost reasoning into a habit.