What the loop does
A Map holds pairs: each key has one value. A for loop over a map runs its body once per entry, and each entry is a pair. Writing (fruit, amount) in front of <- splits the pair into two names, so the body can use the key and the value separately.
val stock = scala.collection.mutable.Map("apples" -> 5, "pears" -> 2)
for ((fruit, amount) <- stock) {
println(s"$fruit $amount")
}
This prints two lines, pears 2 and apples 5. Another run or another Scala version may print them the other way round.
Double parentheses
There are two pairs of parentheses, and they do different jobs. The outer pair belongs to the for. The inner pair, (fruit, amount), takes one entry apart. Without the inner pair, for (entry <- stock) still works, but then entry is the whole pair, written (pears,2) when printed, and you would need entry._1 and entry._2 to reach the parts.
Only the keys, or only the values
To visit only the keys, loop over stock.keys:
for (k <- stock.keys) {
println(k)
}
When you need the values but not the keys, put _ where the key would be: for ((_, amount) <- stock). The underscore means "there is a key here, and I don't use it".
The order is not fixed
A mutable Map makes no promise about the order of its entries. The loop may visit them in an order that differs from the order you added them in. So write loops whose result does not depend on the order. A total, a count and a yes-or-no check give the same answer however the entries come. Printing line by line, or "the first entry", does not.
The exercise
The map scores holds each player's points, and the variables total and count start at 0. The task is to add every player's points to total, and count the players with 10 points or more in count. Only the points matter, so the key is skipped.
- Write the loop with
(_, points), and its closing brace right away. - Inside it, add
pointstototal. - Still inside, if
pointsis 10 or more, add 1 tocount.
val scores = scala.collection.mutable.Map("Ana" -> 12, "Ben" -> 7, "Cleo" -> 15, "Dan" -> 9)
var total = 0
var count = 0
for ((_, points) <- scores) {
total += points
if (points >= 10) {
count += 1
}
}
println(total)
println(count)
It prints 43 and 2: 12 + 7 + 15 + 9 is 43, and only Ana and Cleo have 10 or more. Both numbers are the same whichever order the loop visits the players in.
Common mistakes
- Writing
for (fruit, amount <- stock)with one pair of parentheses. The inner pair is needed to split the entry. - Declaring
totalwithval. It changes inside the loop, so it must bevar. - Counting players inside a check that is placed outside the loop, so it runs once instead of once per player.
- Relying on the order of the entries for anything other than a total, a count or a check.
Key takeaways
for ((key, value) <- map)visits every entry and splits it into its two parts.map.keysgives only the keys;_skips a part you don't need.- A mutable map has no fixed order, so use loops whose answer doesn't depend on it.
