Start learning free

LESSON 268 OF 671 · SORTING & BUILT-INS

Leaderboard in Go: Sorting Structs by Score and Name

Practice Read the full explanation

You get a slice of players, players. Each player is a pair: a name and a score, like ("Ava", 30).

Return the names, from the highest score to the lowest.

Players with the same score go in alphabetical order of their names.

The starter code shows how your language holds a pair.

 

Example 1:

Input: players = [("Ava", 30), ("Ben", 25), ("Cy", 40)]
Output: ["Cy", "Ava", "Ben"]
Explanation: Cy has the most points, 40.
Then come Ava with 30 and Ben with 25.

Example 2:

Input: players = [("Mia", 50), ("Leo", 70), ("Ava", 50)]
Output: ["Leo", "Ava", "Mia"]
Explanation: Leo leads with 70.
Ava and Mia both have 50.
Ava comes first from A to Z.

Example 3:

Input: players = [("Zoe", 0)]
Output: ["Zoe"]
Explanation: Zoe is the only player.

 

Constraints:

  • players has 1 to 100 players.
  • Every score is a whole number from 0 to 1000.
  • Each name is a capital letter followed by lowercase letters, like "Ava".
  • No two players have the same name.
STEP 1 OF 6
    Ctrl + Enter to check

    GO · SORTING & BUILT-INS

    Leaderboard in Go, explained

    Problem overview

    The function leaderboard receives a slice of players, players. Each one is a Player struct, declared for you, with a Name and a Score. It returns only the names, highest score first. Players with the same score go in alphabetical order by name, and no two players share a name.

    For Ava (30), Ben (25) and Cy (40) the result is Cy Ava Ben. For Mia (50), Leo (70) and Ava (50) it is Leo Ava Mia: Leo leads, and Ava comes before Mia on the 50-point tie.

    Approach: sort the players, then collect the names

    The job has two parts. First put the players in the right order, then copy their names into a new slice in that order. Sorting the players, not the names, is the key: the scores are needed to decide the order, and the names alone would lose them.

    sort.Slice takes the slice and a function of two indexes, i and j, that returns true when player i goes before player j. There are two rules, and the second only counts on a tie:

    1. If the scores differ, the higher score goes first.
    2. If the scores are equal, the name that comes first from A to Z goes first.

    Step by step

    1. Sort with sort.Slice. If players[i].Score and players[j].Score differ, return players[i].Score > players[j].Score. The > is what puts high scores first.
    2. Break ties with a last line, return players[i].Name < players[j].Name. Two strings compare with < in dictionary order.
    3. Create names as an empty slice of strings, with names := []string{}.
    4. Loop over the sorted players with for _, player := range players.
    5. Append each name: names = append(names, player.Name). append may return a different slice, so the result is assigned back to names.
    6. Return names after the loop.

    The solution in Go

    func leaderboard(players []Player) []string {
        sort.Slice(players, func(i, j int) bool {
            if players[i].Score != players[j].Score {
                return players[i].Score > players[j].Score
            }
            return players[i].Name < players[j].Name
        })
        names := []string{}
        for _, player := range players {
            names = append(names, player.Name)
        }
        return names
    }

    The lesson declares the struct as type Player struct { Name string; Score int }. The comparison function reads the players through players[i] and players[j], because sort.Slice hands it indexes, not items. Since names are unique, no two players tie on both rules, so the order is fully decided even though sort.Slice is not stable.

    Writing []string{} rather than var names []string returns an empty, non-nil slice if there were no players. Both print as []. The sort also reorders the caller's slice, since slices share their backing array.

    Testing

    Running the function on the statement's examples prints:

    [Cy Ava Ben]
    [Leo Ava Mia]
    [Zoe]

    Edge cases and common mistakes

    • Ascending scores. Using < on the scores puts the lowest score first.
    • Descending names. The tie rule uses < on names: A to Z, even though the scores go high to low.
    • Forgetting to assign append. Calling append(names, player.Name) alone is a compile error in Go (its result is unused), and an old names would stay short anyway.
    • Sorting a names slice only. The scores would no longer be available to compare.
    • Returning the players. The function returns []string, so the loop copies out only the names.
    • A single player. The sort has nothing to do, and the loop returns that one name.
    Keep going with Go500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free