Sorting by key
Real-world sorting is rarely about bare numbers — it is about records: users by signup date, posts by score, files by size. You will write a keyed sort at work this week, guaranteed. Python's sorted handles it with the key argument: a function that, given one item, returns the value to sort by. sorted(words, key=len) sorts words by length because Python calls len on each word and orders by those results.
The rules that make key powerful:
- The key function runs once per item; the O(n log n) comparisons then happen between the precomputed key values. Even an expensive key stays affordable.
- Keys can be tuples, which compare position by position.
key=lambda s: (-s[1], s[0])means "by score, highest first (negating a number reverses its order), then by name A→Z among ties". reverse=Trueflips the entire order when negation is awkward (strings cannot be negated).
There is no separate algorithm to learn here: every sort in this unit simply routes its comparisons through the key.
Code exercise · python
Run this. First sort words by length, then sort (name, score) pairs by score descending with alphabetical tie-breaks — one tuple key does both jobs.
Stability: the invisible guarantee
A sort is stable when items that compare equal keep their original left-to-right order. Python's sort is guaranteed stable, and that guarantee is a tool: to sort by several criteria you can sort by the secondary key first, then by the primary key — the second sort preserves the first sort's order among ties.
Why you care: league tables, spreadsheets, paginated feeds ("order by score, newest first among ties"). With an unstable sort, equal-score rows would shuffle on every re-sort, and users file that as a bug.
Look back at the first output above: pear came before kiwi (both length 4) precisely because pear came first in the input. That is stability in action.
Quiz
scores = [('ana', 91), ('bo', 78), ('cy', 91)]. After sorted(scores, key=lambda s: -s[1]), why does ('ana', 91) come before ('cy', 91)?
Code exercise · python
Your turn. people is a list of (name, age) tuples. Write oldest_first(people): return just the names, oldest person first, breaking age ties alphabetically by name.
Problem
sorted(records, key=make_key) runs on 1,000 records. How many times is make_key called?