The Ranked Dict

An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
easy
Seniority
L3
Asked in
Ripple

Problem

Build the leaderboard from scores, our dict of player names to points, with the highest score first. Points can be any number, negatives and fractions included, and an empty scores simply means an empty board.

Values deserve order too.

Example

Input:

scores = {"bob":87,"dave":70,"alice":95,"carol":95}

Output:

[["alice",95],["carol",95],["bob",87],["dave",70]]

Worked solution and explanation

What this really is

This is a two-level sort dressed up as a leaderboard. Everyone gets "highest score first" right. What separates candidates is the second level: players on the same score have to come out in a fixed order, and the only order the data can justify is the name. Sort on the score alone and Python's stable sort quietly keeps tied players in whatever order the dict handed them over, so 'carol' beats 'alice' just because she arrived first.

There is a second, quieter trap. Plenty of candidates sort the entries and pour them back into a dict, because dicts remember insertion order. That works for display, but a dict compares equal to the same mapping in any order, so nothing downstream can tell your board from an unsorted one. The board is a sequence, so return a sequence.

Building the board

Step 1: Take the entries out of the dict

Call scores.items() and wrap it in list(...). You now hold name-score pairs you can reorder freely, and the caller's dict is never touched.

Step 2: Encode both rules in one key

Ask what the sort compares. The tuple (-entry[1], entry[0]) compares the negated score first, so bigger scores sort earlier, and only when scores match does it fall through to the name, which sorts A to Z.

Step 3: Sort the list and hand it back

standings.sort(...) reorders the list you just built and you return it as is. Each pair comes back as [name, score], matching the visible example.

One composite key, one pass
def rank_players(scores):
    standings = list(scores.items())
    # Higher score first; equal scores fall back to the name, A to Z.
    standings.sort(key=lambda entry: (-entry[1], entry[0]))
    return standings

Negating the score flips its direction while the name keeps ascending order.

Score only, descending
sort(key=lambda entry: entry[1], reverse=True) is stable, so 'carol' (listed first) stays ahead of 'alice'. The board depends on input order.
Score, then name
sort(key=lambda entry: (-entry[1], entry[0])) puts 'alice' ahead of 'carol' every time, whatever order the dict arrived in.

Common follow-up questions