Start learning free

LESSON 230 OF 679 · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

Top Scorer in Rust: Looping Over a HashMap

Practice Read the full explanation

You get scores, a HashMap from players' names to their scores. Return the name of the player with the highest score.

Several players may share the highest score. Then return the name that comes first in alphabetical order.

 

Example 1:

Input: scores = {"Ana": 90, "Ben": 75, "Cara": 88}
Output: "Ana"
Explanation: 90 is the highest score, and it is Ana's.

Example 2:

Input: scores = {"Zoe": 82, "Ana": 82}
Output: "Ana"
Explanation: Both have 82. "Ana" comes before "Zoe" in alphabetical order.

Example 3:

Input: scores = {"Max": 0}
Output: "Max"
Explanation: Max is the only player, so his score is the highest.

 

Constraints:

  • scores has at least one name.
  • Every score is a whole number from 0 to 100.
  • Each name is a capital letter followed by lowercase letters, like "Ana".
STEP 1 OF 5
    Ctrl + Enter to check

    RUST · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

    Top Scorer in Rust, explained

    Problem overview

    The function top_scorer receives scores, a HashMap<String, i32> from player names to scores, and returns the name of the player with the highest score. If several players share the highest score, it returns the one that comes first in alphabetical order. The map always has at least one player, and every score is between 0 and 100.

    For {"Ana": 90, "Ben": 75, "Cara": 88} the answer is "Ana". For {"Zoe": 82, "Ana": 82} both players tie, so the answer is "Ana".

    Approach

    Keep the best player seen so far and compare every entry with it. This is the usual "running best" pattern, with one twist: the order of a HashMap is not fixed, so the code can't rely on which player comes first. That is why the tie rule matters. A player replaces the current best in two cases:

    • their score is higher, or
    • their score is equal and their name comes earlier alphabetically.

    With both rules in place, the final answer is the same whatever order the loop visits the players in.

    Step by step

    1. Start with an empty best_name (String::new()) and a best_score of -1. Scores are never below 0, so the first player visited always beats -1.
    2. Loop over &scores, unpacking each entry into (name, score). The & borrows the map, so name is a &String and score is a &i32.
    3. Inside the loop, decide whether this player is better. Compare *score with best_score, and for a tie compare *name with best_name using <, which is true when the left string comes earlier alphabetically.
    4. If so, store the new best: name.clone() and *score.
    5. After the loop, return best_name.

    The solution in Rust

    impl Solution {
        fn top_scorer(scores: HashMap<String, i32>) -> String {
            let mut best_name = String::new();
            let mut best_score = -1;
            for (name, score) in &scores {
                if *score > best_score || (*score == best_score && *name < best_name) {
                    best_name = name.clone();
                    best_score = *score;
                }
            }
            return best_name;
        }
    }
    

    Details worth knowing

    • Why clone(). The loop only borrows the names from the map, so name is a reference. best_name is a String that owns its text, so it needs its own copy. Assigning the reference directly does not compile: the compiler reports expected `String`, found `&String`.
    • Why *score and *name. Both are references. The star reads the value behind each one so it can be compared with best_score and best_name.
    • The parentheses. The tie check only counts when the scores are equal, so *score == best_score && *name < best_name goes in parentheses and joins the first condition with ||.
    • Alphabetical order. Strings compare by their characters, so "Ana" < "Zoe" is true. Capital letters come before lowercase ones ("Ana" < "ana" is true too). The lesson's names are always a capital followed by lowercase letters, so this never causes trouble.

    Trying it

    Running the function on the lesson's examples gives:

    {"Ana": 90, "Ben": 75, "Cara": 88}  ->  Ana
    {"Zoe": 82, "Ana": 82}              ->  Ana
    {"Max": 0}                          ->  Max
    {"Zoe": 0, "Ana": 0, "Max": 0}      ->  Ana
    

    The single player with a score of 0 shows why the start value is -1 and not 0: with 0, a lone player scoring 0 would never replace the empty name, and the function would return an empty string.

    Common mistakes

    • Ignoring ties. Using only *score > best_score returns whichever tied player the map happens to visit first, and that can change between runs.
    • Starting best_score at 0. That breaks the case where the only top score is 0.
    • Using <= or >= on scores. A tie must be decided by the name, not by who was visited last.
    • Forgetting the & in the loop. The loop would take the map for itself, which is fine here only because the map isn't used again.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free