Start learning free

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

Looping Over a Map in Kotlin: for and Destructuring

Lesson Read the full explanation

TL ; DR:

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


val stock = mutableMapOf("apples" to 5, "pears" to 2)

for ((fruit, amount) in stock) {
    println("$fruit $amount")
}

// apples 5
// pears 2


Full lesson:

A loop can visit every entry of a map, 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). Kotlin warns about a name you never use.

The order: a map made with mutableMapOf keeps the keys in the order they were added. Many other maps don't. A total or a count comes out the same in any order. Those are safe answers.

Watch out: don't add or remove keys inside the loop. Kotlin stops with a ConcurrentModificationException.


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

    KOTLIN · LOOPS WITH STRINGS, ARRAYS & DICTIONARIES

    Looping Over Dictionaries in Kotlin, explained

    What a loop over a map does

    A Kotlin Map stores pairs: each key has one value. A for loop over a map visits every pair once, and the loop body runs once per entry. The usual way to write it is to split each entry into its key and its value right in the loop header:

    val stock = mutableMapOf("apples" to 5, "pears" to 2)
    
    for ((fruit, amount) in stock) {
        println("$fruit $amount")
    }
    

    It prints:

    apples 5
    pears 2
    

    The parentheses around (fruit, amount) matter. They tell Kotlin to take the entry apart: the key goes into the first name, the value into the second. Without them, for (fruit, amount in stock) is a syntax error, because a loop header names one loop variable unless you destructure it.

    Other ways to loop

    You do not always need both parts of an entry.

    • for (fruit in stock.keys) visits only the keys.
    • for (amount in stock.values) visits only the values.
    • for (entry in stock) gives you the whole entry, and you read entry.key and entry.value.

    When you want only the values but still loop over the map itself, write _ in place of the name you do not need: for ((_, amount) in stock). The underscore says "I am skipping this part", and Kotlin does not warn about it. A real name that you never use does get a warning.

    About the order

    A map made with mutableMapOf keeps its keys in the order they were added, so the loop above printed apples before pears. A hashMapOf does not promise any order. Here is one printed after adding the keys zebra, apple, mango and kiwi, in that order:

    {zebra=1, apple=2, kiwi=4, mango=3}
    

    So write loops whose answer does not depend on the order. A total, a count and a yes-or-no check come out the same in any order. If you need sorted output, sort first: for ((k, v) in h.toSortedMap()) visits the keys alphabetically (apple, kiwi, mango, zebra).

    Do not change the keys inside the loop

    Adding or removing keys while you loop over the same map is a trap. Kotlin stops with a ConcurrentModificationException. For example, removing "apples" from stock inside for ((k, _) in stock) throws it. Changing the value of a key that is already there is fine. If you must remove keys, loop over a copy of the keys, stock.keys.toList(), and remove from the map itself:

    val copy = mutableMapOf("a" to 1, "b" to 2, "c" to 3)
    for (k in copy.keys.toList()) {
        if (k != "b") copy.remove(k)
    }
    println(copy)   // {b=2}
    

    The lesson's task

    The map scores holds each player's points. The task is to add every player's points to total and to count, in count, the players with 10 points or more. The names do not matter, so the loop skips them with _.

    1. Write for ((_, points) in scores) { and close it with } straight away, so the following steps go inside.
    2. Inside, add points to total.
    3. Still inside, if points is 10 or more, add 1 to count.
    val scores = mutableMapOf("Ana" to 12, "Ben" to 7, "Cleo" to 15, "Dan" to 9)
    var total = 0
    var count = 0
    
    for ((_, points) in scores) {
        total += points
        if (points >= 10) {
            count += 1
        }
    }
    
    println(total)
    println(count)
    

    The output is:

    43
    2
    

    The points are 12, 7, 15 and 9, which add up to 43. Two players, Ana and Cleo, have 10 or more. The total and the count are the same whichever order the players come in, so the loop is safe to rely on.

    Common mistakes

    • Forgetting the parentheses around the pair in the loop header.
    • Putting the line that updates count outside the loop, which counts only the last player's result instead of every player's.
    • Adding or removing keys of scores inside the loop.
    • Declaring total with val. It changes during the loop, so it needs var.

    Key takeaways

    • for ((key, value) in map) visits every entry once.
    • Use _ for the part you do not need, or loop over map.keys or map.values.
    • Only write code that does not depend on the order, unless you sort first.
    • Do not add or remove keys while looping over the map.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free