Python Basics: Building Useful Sorting Keys
A sorting key turns each item into the value Python should compare. Computed keys help when displayed values, missing data, or mixed sort directions need a specific policy.
These three standalone examples were tested on Linux with Python 3.12.14. They require no third-party packages. Assertions check the results; run without Python’s -O option.
Prepare a scratch directory
You need Bash, Python 3.12 or newer on your PATH, a text editor, and the mktemp, rm, and rmdir utilities. Keep using the same terminal and save each named source file as UTF-8.
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 11. Sort numbered filenames numerically
Save as sort_report_names.py:
names = ["report-10.txt", "report-2.txt", "report-1.txt"]
def report_number(name):
stem = name.removesuffix(".txt")
return int(stem.removeprefix("report-"))
ordered = sorted(names, key=report_number)
assert ordered == ["report-1.txt", "report-2.txt", "report-10.txt"]
assert names[0] == "report-10.txt"
print(ordered)Run it:
python3 sort_report_names.pyOutput:
['report-1.txt', 'report-2.txt', 'report-10.txt']The key extracts an integer so 2 comes before 10. This parser assumes the exact report-N.txt convention; it is not a general natural-sort parser. sorted returns a new list.
2. Place missing values last
Save as sort_optional_scores.py:
rows = [("Ada", 9), ("Bea", None), ("Cal", 3), ("Dee", None)]
def score_key(row):
score = row[1]
return (score is None, score if score is not None else 0)
ordered = sorted(rows, key=score_key)
assert ordered == [("Cal", 3), ("Ada", 9), ("Bea", None), ("Dee", None)]
print(ordered)Run it:
python3 sort_optional_scores.pyOutput:
[('Cal', 3), ('Ada', 9), ('Bea', None), ('Dee', None)]The first tuple component separates known scores from missing ones. False sorts before True. The second component is always numeric, avoiding an invalid comparison between None and a number. Equal keys preserve input order.
3. Combine opposite directions with stable passes
Save as sort_ranked_names.py:
rows = [("Bea", 8), ("Ada", 8), ("Cal", 10)]
rows.sort(key=lambda row: row[0])
result = rows.sort(key=lambda row: row[1], reverse=True)
assert result is None
assert rows == [("Cal", 10), ("Ada", 8), ("Bea", 8)]
print(rows)
print(result)Run it:
python3 sort_ranked_names.pyOutput:
[('Cal', 10), ('Ada', 8), ('Bea', 8)]
NoneSort by the secondary field first, then the primary field. Stability keeps names ascending inside equal-score groups while scores descend. list.sort changes the list in place and returns None.
When to use this
Choose a key that returns consistently comparable values. Python evaluates the key once per input item for each sort. Keep key functions free of mutations so their behavior stays easy to reason about.
References
Clean up
In the same terminal, remove only these example files, then return to your original directory and remove the empty scratch directory:
rm -- sort_report_names.py sort_optional_scores.py sort_ranked_names.py
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirAcknowledgements
This post was created with assistance from AI.