runtime
67 / 250
lesson 67 Built-ins & Sorting · intermediate

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.

You'll be able to
  • Pass a function as key= so sorted orders 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
The idea

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.

example-1.py · Sorting dictionaries directly
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.

example-2.py · A leaderboard, highest first
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.

example-3.py · Invoices to pay: soonest first, then the largest
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.

Review
  • sorted(items, key=fn) calls fn on 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: any and all, for yes-or-no questions about a whole collection.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Sort records by a key — Built-ins & Sorting · Runtime