Start learning free

LESSON 270 OF 678 · TUPLES, SORTING & BUILT-INS

Leaderboard in Swift: Sorting Tuples by Score, Then by Name

Practice Read the full explanation

You get an array 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

    SWIFT · TUPLES, SORTING & BUILT-INS

    Leaderboard in Swift, explained

    Problem overview

    The function leaderboard receives an array of players. Each player is a tuple (name: String, score: Int). 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 unique.

    For [("Ava", 30), ("Ben", 25), ("Cy", 40)] the result is ["Cy", "Ava", "Ben"]. For [("Mia", 50), ("Leo", 70), ("Ava", 50)] it is ["Leo", "Ava", "Mia"]: Leo leads, and Ava and Mia tie on 50, so Ava comes first.

    Approach

    There are two jobs: put the players in order, then keep only the names. Do them in that order, because the names alone no longer carry the scores.

    The sorting uses a closure with two rules, as in the previous sorting lesson. The closure receives two players, a and b, and returns true when a must come first. The first rule compares scores, and a higher score goes first. The second rule is the tie-breaker, and it only matters when the scores are equal: the name that comes first from A to Z goes first.

    After sorting, a loop walks over the ordered players and collects each name in a new array.

    The tie in the second example shows why the order of the two rules matters. Leo (70) is compared with Mia (50) and Ava (50): the scores differ, so the first rule decides and Leo goes first. Mia and Ava have equal scores, so the first rule says nothing and the closure falls through to the second rule, which compares the names. If the name rule came first, the scores would never be used for players with different names, and since names are unique, that is every pair.

    Step by step

    1. Sort with players.sorted and a closure that names its items a, b in.
    2. First rule: if a.score != b.score, return a.score > b.score. The comparison is > because a bigger score goes first.
    3. Second rule: for equal scores, return a.name < b.name. Here < is right, because A to Z means the smaller string first.
    4. Create an empty names array with var names: [String] = []. The type annotation is needed, since an empty literal gives Swift nothing to infer the element type from.
    5. Loop over ordered with for player in ordered.
    6. Append player.name to names. The result holds names only.
    7. Return names after the loop, once every name is in.

    The solution in Swift

    class Solution {
        func leaderboard(_ players: [(name: String, score: Int)]) -> [String] {
            let ordered = players.sorted { a, b in
                if a.score != b.score {
                    return a.score > b.score
                }
                return a.name < b.name
            }
            var names: [String] = []
            for player in ordered {
                names.append(player.name)
            }
            return names
        }
    }
    

    Swift details:

    • The labels give readable closures. Because the parameter type is [(name: String, score: Int)], the closure can write a.score and b.name instead of $0.1 and $1.0.
    • sorted returns a new array of tuples, and players is unchanged.
    • Two comparison directions in one closure. Scores go high to low (>) and names go A to Z (<). That is normal: each rule has its own direction.

    Edge cases and common mistakes

    • One player. [("Zoe", 0)] gives ["Zoe"].
    • Forgetting the tie-breaker. Sorting by score alone leaves tied players in whatever order the sort produces. For the second example, a closure that compares only scores returns ["Leo", "Mia", "Ava"], but the expected answer has "Ava" before "Mia".
    • Using < for scores. That gives the lowest score first. The second example would start with Ava or Mia instead of Leo.
    • Returning the sorted pairs. The function returns [String], so the scores must be dropped.

    Testing

    • [("Ava", 30), ("Ben", 25), ("Cy", 40)] gives ["Cy", "Ava", "Ben"].
    • [("Mia", 50), ("Leo", 70), ("Ava", 50)] gives ["Leo", "Ava", "Mia"].
    • [("Zoe", 0)] gives ["Zoe"].
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free