Sorting with key functions, and the collections module
sorted against list.sort, key functions and stable multi-key sorts, and the Counter, defaultdict and deque that replace hand-written bookkeeping.
After this lesson you can
- Sort by several keys in mixed directions using a tuple key or stable passes
- Explain why list.sort() returns None
- Count, group and keep a sliding window with Counter, defaultdict and deque
- Say how Counter.most_common orders ties
sorted(iterable) returns a new list and works on anything
iterable. some_list.sort() sorts that list in place and returns
None — so names = names.sort() replaces your list with None.
Key functions
Both take key=, a function called once per element; the elements are
then ordered by what it returns. reverse=True flips the result.
sorted(words, key=len) # shortest first
sorted(words, key=str.lower) # case-insensitive
sorted(rows, key=lambda r: r["age"])
To sort by several things, return a tuple: tuples compare element by
element, so key=lambda p: (p.dept, p.name) sorts by department and
then by name within it. For mixed directions on numbers, negate one
part: key=lambda p: (-p.score, p.name) is "score high to low, then
name A to Z".
Python's sort is stable: elements with equal keys keep the order they arrived in. That gives a second way to sort by several keys, which also works when a part cannot be negated (a string you want descending): sort by the least important key first, then by the more important one.
def run(): names = ["mia", "Bo", "al"] returned = names.sort() people = [("Nia", 30), ("Al", 25), ("Bo", 30), ("Cy", 25)] by_age = sorted(people, key=lambda p: p[1]) age_desc_name_asc = sorted(people, key=lambda p: (-p[1], p[0])) both_reversed = sorted(people, key=lambda p: (p[1], p[0]), reverse=True) # name descending, then age ascending: two stable passes two_pass = sorted(people, key=lambda p: p[0], reverse=True) two_pass = sorted(two_pass, key=lambda p: p[1]) return { "sort_returned": returned, "names_now": names, "by_age_stable": by_age, "age_desc_name_asc": age_desc_name_asc, "both_reversed": both_reversed, "two_pass": two_pass, }The collections module
Counter(iterable)counts hashable items.most_common(n)returns thenlargest counts, and ties come out in the order the items were first seen — not alphabetically. Counters also add and subtract.defaultdict(factory)callsfactory()to create a missing key's value on first access, which makes grouping a one-liner:groups[key].append(item). Even a plain read of a missing key creates it.dequeis a double-ended queue:append/appendleftandpop/popleftare O(1) at both ends, wherelist.pop(0)is O(n). Withmaxlen, appending to a full deque drops an item from the other end — a ready-made "last N" buffer.namedtuple("Point", "x y")is a tuple whose fields also have names.
from collections import Counter, defaultdict, deque def run(): votes = ["tea", "coffee", "water", "coffee", "tea", "juice"] counts = Counter(votes) groups = defaultdict(list) for word in ["apple", "avocado", "banana", "blueberry", "cherry"]: groups[word[0]].append(word) _ = groups["z"] # only reading it window = deque(maxlen=3) for reading in [5, 7, 9, 11, 13]: window.append(reading) return { "most_common_2": counts.most_common(2), "minus": dict(counts - Counter(["tea", "tea"])), "groups": dict(groups), "last_three": list(window), }Common mistakes
result = items.sort():resultisNone, anditemsis now sorted in place.- Sorting descending with
reverse=Trueand a tuple key, when only the first part should be descending. The tie-breaker flips too. - Using
Counter.most_common()for "highest count, ties alphabetically". Its ties follow first appearance. - Reading a missing key of a
defaultdict"just to check". The check itself inserts the key.
What interviewers ask
sorted()orlist.sort()? New list from any iterable against in place on a list, returningNone; both stable, both takekeyandreverse.- What does "stable sort" mean, and why is it useful? Equal keys keep their input order, so sorting in passes by secondary then primary key gives a correct multi-key sort.
- How would you implement a sliding window or a queue?
deque, withmaxlenfor a fixed window; neverlist.pop(0)in a loop.
Exercise · Pro
A leaderboard from many score entries
Exercises are free in the first 3 lessons of every course. From here on they are part of Pro and Sprint; the lesson and its runnable examples stay open.
Upgrade