Problem overview
The method leaderboard gets players, a list of pairs like ("Ava", 30): a name and a score. It returns only the names, from the highest score to the lowest. Players with the same score go in alphabetical order of their names. Names are all different.
For [("Mia", 50), ("Leo", 70), ("Ava", 50)] the answer is ["Leo", "Ava", "Mia"]: Leo leads with 70, and Ava comes before Mia among the two 50s.
Approach
There are two rules in opposite directions: scores go high to low, names go A to Z. A single sort key handles both. The key (-player[1], player[0]) puts the negated score first. A bigger score becomes a smaller negative number, which sorts earlier. When two scores tie, Python compares the next part of the tuple, the name, in the usual A to Z order.
Using reverse=True instead would flip both rules and put tied names in Z to A order. For the example above, reverse=True with the score alone gives Leo, Mia, Ava, which is wrong.
For the second example, the keys are these:
| player | key |
|---|---|
| ("Mia", 50) | (-50, 'Mia') |
| ("Leo", 70) | (-70, 'Leo') |
| ("Ava", 50) | (-50, 'Ava') |
-70 is the smallest, so Leo comes first. The two -50 keys tie on the first part, so 'Ava' and 'Mia' decide, and Ava goes first.
Step by step
- Build
ordered:playerssorted withkeyreturning(-player[1], player[0]). Hereplayer[1]is the score. - Start an empty list
names. - Loop over
ordered, unpacking each pair intonameandscore. - Append
nametonames. - After the loop, return
names.
The solution in Python
class Solution:
def leaderboard(self, players: List[Tuple[str, int]]) -> List[str]:
ordered = sorted(players, key=lambda player: (-player[1], player[0]))
names = []
for name, score in ordered:
names.append(name)
return names
After sorting, ordered is a list of pairs; for the example it is [('Leo', 70), ('Ava', 50), ('Mia', 50)]. The loop unpacks each pair and keeps only the name. score is unused, which is fine.
Testing
[("Ava", 30), ("Ben", 25), ("Cy", 40)] -> ['Cy', 'Ava', 'Ben']
[("Mia", 50), ("Leo", 70), ("Ava", 50)] -> ['Leo', 'Ava', 'Mia']
[("Zoe", 0)] -> ['Zoe']
Why negating works
Sorting ascending by -score is the same as sorting descending by score, as long as the score is a number. That is why the trick fits this lesson and not the names: a string can't be negated, and -"Mia" raises a TypeError. When only one part of the key is a number, you flip that part and leave the text alone.
Another way to finish is a list comprehension: [name for name, score in ordered] gives the same names as the loop, in one line.
Edge cases
One player gives a list with that one name. A score of 0 works like any other, since -0 is just 0. Names are all different, so two players never tie on both parts of the key, and the order is always fully decided. The list comes out as long as the input, with every name once.
A key on the whole pair
Without a key, Python sorts pairs by name first and then by score, which is the wrong priority here. The key function is what puts the score first, and the minus sign is what turns "low to high" into "high to low".
Common mistakes
- Forgetting the minus sign, which sorts the lowest score first.
- Negating the name: you can't put
-before a string. - Returning
orderedinstead ofnames: the result holds only names.
