Sort records by a key
`sorted` can't compare two dictionaries, but it can compare a value you pick out of each one. That value is the key, and a tuple key sorts by several fields at once.
- Pass a function as
key=sosortedorders records by one of their fields - Sort by several fields with a key that returns a tuple, and reverse one field by negating a number
- Rely on stability: records with equal keys keep their original order
sorted (see Lists & Tuples) orders numbers and texts because Python knows how to compare them. A dictionary is different: is {"name": "Ana", "points": 42} smaller than Ben's record? Python refuses to guess.
Run each example to see what it prints. Running examples doesn't count toward progress.
players = [{"name": "Ana", "points": 42}, {"name": "Ben", "points": 57}]
print(sorted(players))The fix is a key function: a function that takes one record and returns the value to sort by. Pass the function itself, without calling it: key=points_of, not key=points_of(). sorted calls it once per record, sorts by the results, and returns the records. reverse=True puts the largest first.
Python's sort is stable: records whose keys are equal stay in the order they arrived, even with reverse=True.
def points_of(player): return player["points"] players = [ {"name": "Ana", "points": 42}, {"name": "Ben", "points": 57}, {"name": "Chen", "points": 42}, {"name": "Dara", "points": 61}, ] for player in sorted(players, key=points_of, reverse=True): print(player["name"], player["points"]) print(players[0]["name"])
To sort by several fields, return a tuple. Tuples compare item by item: the first items decide, and only on a tie do the second items matter. To make one numeric field run the other way, negate it in the tuple. Dates written as YYYY-MM-DD text sort correctly as text, because the most significant part comes first.
def payment_order(invoice): return (invoice["due"], -invoice["amount"]) invoices = [ {"id": "INV-104", "due": "2025-03-01", "amount": 120.0}, {"id": "INV-101", "due": "2025-02-15", "amount": 89.5}, {"id": "INV-103", "due": "2025-03-01", "amount": 640.0}, {"id": "INV-102", "due": "2025-02-15", "amount": 89.5}, ] for invoice in sorted(invoices, key=payment_order): print(invoice["id"], invoice["due"], invoice["amount"])
When to use it: leaderboards, schedules, invoices: any time records need an order. items.sort(key=…) does the same thing in place and returns None; sorted returns a new list and leaves the original alone. Mistakes to avoid: calling the key function (key=points_of()); and reverse=True with a tuple key, which reverses every field, so names on a tie come out Z to A.
sorted(items, key=fn)callsfnon each item and orders by the results; pass the function, don't call it.- A tuple key sorts by several fields; negate a number to reverse just that field.
- The sort is stable, so equal keys keep their input order, even with
reverse=True. - Next:
anyandall, for yes-or-no questions about a whole collection.