Start learning free

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

Looping Over Dictionaries in Swift: for-in and (key, value)

Lesson Read the full explanation

TL ; DR:

A for-in loop over a dictionary visits every entry. (fruit, amount) splits each one into its key and its value.


let stock = ["apples": 5, "pears": 2]

for (fruit, amount) in stock {
    print(fruit, amount)
}

// pears 2
// apples 5   (in any order)


Full lesson:

A loop can visit every entry of a dictionary, one at a time. The loop body runs once per key.

(fruit, amount) splits each entry. The key comes first, then the value.

Loop over stock.keys to get only the keys.

Don't need the key? Write _ in its place, as in for (_, amount) in stock. Swift warns about a name you never use.

The order: a Swift dictionary has no fixed order. It can even change from one run to the next. A total or a count comes out the same in any order. Those are safe answers.


Your task

A game keeps each player's points in scores. The variables total and count start at 0.

Loop over scores. Add every player's points to total. Count the players with 10 points or more in count.

The loop needs only the points, not the names. The code at the bottom prints both.

Expected output:

43
2
STEP 1 OF 3
    Ctrl + Enter to check

    SWIFT · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

    Looping Over Dictionaries in Swift, explained

    What a dictionary loop does

    A dictionary stores entries, each one a key with its value. A for-in loop over a dictionary runs its body once per entry. Swift hands the loop each entry as a pair, so you can split it into two names right in the loop header:

    let stock = ["apples": 5, "pears": 2]
    
    for (fruit, amount) in stock {
        print(fruit, amount)
    }
    

    The key always comes first and the value second. With this dictionary the loop prints these two lines, in either order:

    apples 5
    pears 2
    

    Under the hood, each entry is a tuple labelled (key: String, value: Int). The pattern (fruit, amount) takes it apart. If you prefer, write for entry in stock and use entry.key and entry.value.

    Only the keys, or only the values

    To visit just the keys, loop over stock.keys. To visit just the values, loop over stock.values. When you do want the pair but not one half of it, write _ in its place:

    for (_, amount) in stock {
        print(amount)
    }
    

    The underscore says "I don't need this part". It matters because Swift warns about a name you declare and never use, and _ avoids that warning.

    The order is not fixed

    A Swift dictionary has no fixed order, and the order can differ from one run of the program to the next. So code that depends on which entry comes first is wrong, even if it seemed to work once. Two kinds of answer are safe in any order:

    • a total, built by adding every value;
    • a count of the entries that pass a test.

    If you do need a stable order, sort first. stock.sorted(by: { $0.key < $1.key }) gives an array of entries ordered by key, and looping over that array prints apples 5 and then pears 2 every time. Sorting is not needed for this lesson.

    The lesson's exercise

    The code starts with these lines:

    let scores: [String: Int] = ["Ana": 12, "Ben": 7, "Cleo": 15, "Dan": 9]
    var total = 0
    var count = 0
    

    The task is to add up all the points in total and count in count the players with 10 points or more. The names don't matter, so the loop header splits each entry into (_, points):

    for (_, points) in scores {
        total += points
        if points >= 10 {
            count += 1
        }
    }
    

    Step by step: the loop gives points the value of one player each time. The first line of the body adds it to total. The if adds 1 to count only when that player has 10 or more. The points are 12, 7, 15 and 9, so the total is 43. Ana (12) and Cleo (15) reach 10, so the count is 2. The two print calls at the bottom of the code give:

    43
    2
    

    Because the answers are a sum and a count, the result is the same whichever order Swift uses.

    Common mistakes

    • Swapping the names. In (points, name) the first name would hold the key, so points would be a String and total += points would not compile. The key is first.
    • Relying on the order. A loop that keeps "the first player it sees" gives different answers on different runs.
    • Changing the dictionary while looping over it. The loop works on a copy of the dictionary as it was when the loop began, so changes made inside the body don't affect which entries are visited. Build the changes in a separate variable instead.
    • Forgetting var on the totals. total and count change inside the loop, so they must be declared with var. A let would be a compile error.

    Key takeaways

    • for (key, value) in dict visits every entry once.
    • _ skips the half you don't need.
    • dict.keys and dict.values loop over one half only.
    • The order is not fixed, so use totals and counts, or sort first.
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free