Sorting and Ranking
Overview
Order by the value you mean, and remember that sorted returns a new list.
What You Will Learn in This Lesson
By the end of this lesson, you will be able to:
- Sort records by a field with
keyandreverse. - Avoid the
.sort()-returns-None trap. - Break ties with a tuple key, including a descending number and an ascending name.
- Take the top n with a slice, and give tied values the same rank.
Why This Matters
Most reports end in a ranking: the top five products, the lowest-scoring topics, the students who most need help. Getting the order right means sorting by the right field, in the right direction, with a sensible rule for ties — and not losing the list along the way. pandas’ sort_values and nlargest in unit 6 take the same arguments for the same reasons.
Step 1: Sorting by a field
Records do not have a natural order. key tells sorted which part of each one to compare.
key and reverse
key is a function applied to each item; its result is what gets compared. reverse=True puts the largest first.
rows = [{"name": "Ada", "score": 92}, {"name": "Alan", "score": 79}, {"name": "Grace", "score": 88}]
best = sorted(rows, key=lambda r: r["score"], reverse=True)
print([r["name"] for r in best])
sorted versus .sort()
sorted(x) returns a new list and leaves x alone. x.sort() reorders x itself and returns None. So names = names.sort() throws the list away.
names = ["Grace", "Ada", "Alan"]
print(sorted(names), names)
result = names.sort()
print(result, names)
Mini Practice #1: Lowest first
Try It YourselfPrint the names from lowest score to highest, then check that rows itself is still in its original order.
Step 2: Ties
Two rows with the same score come out in whatever order they went in. If the order matters, say what breaks the tie.
A tuple key
Tuples compare element by element, so key=lambda r: (r["score"], r["name"]) sorts by score and then by name within equal scores.
rows = [{"name": "Grace", "score": 88}, {"name": "Ada", "score": 88}, {"name": "Alan", "score": 79}]
print([r["name"] for r in sorted(rows, key=lambda r: (r["score"], r["name"]))])
Descending numbers, ascending names
reverse=True would flip both parts. Negating the number flips only the score: highest score first, and alphabetical among ties.
rows = [{"name": "Grace", "score": 88}, {"name": "Ada", "score": 88}, {"name": "Katherine", "score": 99}]
ranked = sorted(rows, key=lambda r: (-r["score"], r["name"]))
print([(r["name"], r["score"]) for r in ranked])
Mini Practice #2: Break the tie
Try It YourselfSort by score, highest first, with ties in alphabetical order by name.
Step 3: Top n and ranks
A ranking is a sort followed by either a slice or a numbering.
Slicing the top
Sort, then take [:n]. A slice longer than the list simply returns what there is, so asking for the top ten of a short list needs no special case.
scores = [92, 79, 88]
print(sorted(scores, reverse=True)[:2])
print(sorted(scores, reverse=True)[:10])
Equal scores, equal rank
Numbering the sorted list with enumerate gives tied students different ranks. The fairer rule (“competition ranking”) gives a tie the same rank, and the next student the rank after all the tied ones: 1, 2, 2, 4.
scores = sorted([92, 88, 88, 79], reverse=True)
ranks = []
for i, s in enumerate(scores):
if i > 0 and s == scores[i - 1]:
ranks.append(ranks[-1])
else:
ranks.append(i + 1)
print(list(zip(scores, ranks)))
Key idea: Sorting a column that is still text sorts it alphabetically — "100" before "20". Convert types (lesson 3) before sorting numbers.
Step 4: When to Use It
Top and bottom n
Leaderboards, the weakest topics, the largest orders: sorted with a key and reverse, then a slice.
sorted(rows, key=lambda r: r["score"], reverse=True)[:5]
Rankings people will read
A tuple key to break ties, and shared ranks for equal values.
When Not to Use It
Do not write x = x.sort() — it replaces your list with None. And do not sort a column that is still text: "100" comes before "20".
End-of-Lesson Exercises
Exercise 1: The top n names
Write top_names(rows, n) that returns the names of the n highest scorers, highest first.
sorted with a key and reverse, then take a slice. A slice longer than the list is not an error, which is why asking for five out of one works.
Exercise 2: A fair ranking
Write rank(rows) returning a list of (rank, name, score) tuples, highest score first, with ties broken alphabetically by name. Tied scores share a rank, and the next score takes the rank after all the tied ones (1, 2, 2, 4).
Sort with key=lambda r: (-r["score"], r["name"]). Then walk it with enumerate: if the score equals the previous one, reuse the previous rank; otherwise the rank is i + 1.