Start learning free

LESSON 227 OF 677 · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

Top Scorer in Scala: Loop Over a Map, Break Ties by Name

Practice Read the full explanation

You get scores, a mutable.Map 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

    SCALA · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

    Top Scorer in Scala, explained

    Problem overview

    The method topScorer gets scores, a mutable Map[String, Int] from player names to scores, and returns the name of the player with the highest score. When several players share the highest score, it returns the name that comes first alphabetically. The map 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 have 82, and Ana comes before Zoe. For {"Max": 0} the only player wins, even with 0.

    Approach

    Keep the best player seen so far, and compare every entry with it. This is a "best so far" scan, the same pattern as finding a maximum in a list, with a second rule for ties. A map has no fixed order, so the code must give the right answer whichever entry comes first. That is why the tie rule uses the names themselves and not the position in the loop.

    Step by step

    1. Create two variables, bestName as an empty string and bestScore as -1. They change during the loop, so they are var. Scores are never below 0, so the first player always beats -1.
    2. Loop with for ((name, score) <- scores), which splits each entry into its key and value.
    3. Inside, check whether this player is better: the score is higher, or the scores are equal and the name comes earlier. In Scala, name < bestName compares two strings alphabetically.
    4. If so, store both the name and the score as the new best.
    5. After the loop, return bestName.

    The solution in Scala

    class Solution {
        def topScorer(scores: scala.collection.mutable.Map[String, Int]): String = {
            var bestName = ""
            var bestScore = -1
            for ((name, score) <- scores) {
                if (score > bestScore || (score == bestScore && name < bestName)) {
                    bestName = name
                    bestScore = score
                }
            }
            return bestName
        }
    }
    

    The parentheses around score == bestScore && name < bestName make the tie rule one unit: it only counts when the two scores are equal. The tie rule never fires on the first entry, because bestScore starts at -1 and no score equals it.

    Testing

    The three examples give these results:

    • Ana -> 90, Ben -> 75, Cara -> 88 returns Ana.
    • Zoe -> 82, Ana -> 82 returns Ana.
    • Max -> 0 returns Max.

    Another way

    You can also sort the entries so that the best one comes first, then take it. Sorting by (-score, name) puts higher scores first and, among equal scores, earlier names first:

    val top = scores.toSeq.sortBy { case (n, s) => (-s, n) }.head._1
    

    For Zoe -> 82, Ana -> 82, Ben -> 70 this gives Ana. It works, but it sorts the whole map to find one entry. The single loop does the same job with one pass and no extra collection, and it shows the "best so far" pattern you will use again and again.

    Edge cases and common mistakes

    • Starting bestScore at 0. A lone player with 0 points would never beat it, and the method would return the empty string. Starting at -1 avoids that.
    • Using >= alone. It would keep whichever tied player the loop visits last, and the order of a map is not fixed, so the answer would depend on luck.
    • Forgetting the parentheses around the tie check. && binds tighter than ||, so this particular line would still work, but the parentheses make the intent clear.
    • Using val for the two best-so-far variables. They are reassigned, so the code would not compile.
    Keep going with Scala500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free