Master

Sorting records by several keys

Real records sort by more than one field. Sort by the least important field first, or hand the sort a tuple of keys, and the order becomes total.

What you will see

[{'lvl': 2, 'id': 'a'}, {'lvl': 2, 'id': 'b'}, {'lvl': 1, 'id': 'a'}]

About 3 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Sort records by multiple fields.

1

Sort tuples by both fields.

rows = [(3, "a"), (1, "b"), (3, "a"), (1, "c")] print(sorted(rows))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
[(1, c), (1, b), (3, a), (3, a)]
2

Sort by time then name.

rows = [{"n": "owl", "t": 9}, {"n": "bee", "t": 4}, {"n": "owl", "t": 2}] rows.sort(key=lambda r: (r["t"], r["n"])) print(rows)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
[{'n': 'owl', 't': 2}, {'n': 'bee', 't': 4}, {'n': 'owl', 't': 9}]
3

Sort ISO dates.

rows = ["2026-10-11", "2025-04-01", "2026-01-05"] print(sorted(rows))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
['2025-04-01', '2026-01-05', '2026-10-11']
4

Sort level descending then id.

rows = [{"lvl": 2, "id": "b"}, {"lvl": 1, "id": "a"}, {"lvl": 2, "id": "a"}] rows.sort(key=lambda r: (-r["lvl"], r["id"])) print(rows)

Before you run it, say out loud what it will print. Then open the answer.

What it prints
[{'lvl': 2, 'id': 'a'}, {'lvl': 2, 'id': 'b'}, {'lvl': 1, 'id': 'a'}]

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Records sort by several keys by returning a tuple from the key function, or by stable passes from least important to most important.
1 records
↓
2 key returns tuple
↓
3 compare left to right
↓
4 total order
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

rows = [(3, "a"), (1, "b"), (3, "a"), (1, "c")] sets nothing on screen
print(sorted(rows)) [(1, c), (1, b), (3, a), (3, a)]
Why this works
Tuple keys are the habit

Returning a tuple from the key is the clean way to sort by several fields. Each field is a comparison level, left to right.

Stable sorts allow passes

Sorting by one key at a time, least important first, works only because the sort is stable. Know the guarantee you are leaning on.

Examples

Sort by a tuple

rows = [(3, "a"), (1, "b"), (3, "a"), (1, "c")]
print(sorted(rows))

A tuple compares left to right. Ties in the first field fall through to the second.

Two keys with a key function

rows = [{"n": "owl", "t": 9}, {"n": "bee", "t": 4}, {"n": "owl", "t": 2}]
rows.sort(key=lambda r: (r["t"], r["n"]))
print(rows)

The key returns a tuple. Sort time first, then name, giving a total order.

Least important first

rows = [(2, "b"), (1, "a"), (2, "a")]
rows.sort(key=lambda r: r[1])
rows.sort(key=lambda r: r[0])
print(rows)

Stable sorts let you sort by the last key first, then the earlier one. The second sort keeps the first order on ties.

Dates sort as text

rows = ["2026-10-11", "2025-04-01", "2026-01-05"]
print(sorted(rows))

ISO dates sort correctly as text because the biggest unit comes first. That is why the format is year first.

Missing values sort somewhere

rows = [3, None, 1]
print(sorted(rows, key=lambda x: (x is None, x if x is not None else 0)))

Push the missing values to the end with a flag in the key. Decide where they belong on purpose.

Case-insensitive order

words = ["Owlww", "apple", "Bee"]
print(sorted(words, key=str.lower))

Lower-casing in the key gives dictionary order. The default puts all capitals before all lowercase.

Total order needed

rows = [(1, "a"), (1, "a")]
print(sorted(rows))

If two records tie on every key, the order between them is arbitrary but stable. Add a final tiebreaker for a real total order.

Sort a table row list

rows = [{"lvl": 2, "id": "b"}, {"lvl": 1, "id": "a"}, {"lvl": 2, "id": "a"}]
rows.sort(key=lambda r: (-r["lvl"], r["id"]))
print(rows)

Negate a number to reverse just that field. Level descending, then id ascending.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Built-in sorts
Previous Lesson
Built-in sorts
Next Lesson
Sorting data that does not fit
Sorting data that does not fit →