Skipping an iteration
Some languages have a continue keyword that jumps to the next pass of a loop. Scala doesn't. The usual replacement is simpler than it sounds: put the work inside an if that is true only for the items you want to keep. For the others the body does nothing, which has the same effect as skipping them.
An example: ages at a bar
Only people aged 21 or more get in. The loop looks at each age and acts only on the ones that qualify:
val ages = Array(10, 30, 21, 19, 25)
for (age <- ages) {
if (age >= 21) {
println("Someone of age " + age + " entered the bar.")
}
}
Someone of age 30 entered the bar.
Someone of age 21 entered the bar.
Someone of age 25 entered the bar.
The loop still visits all five ages. For 10 and 19 the condition age >= 21 is false, so nothing is printed. Age 21 is printed because the condition uses >=, which includes the boundary value. With > the 21-year-old would be turned away.
How it compares with break
The two ideas are different, and it helps to keep them apart:
- Skipping (this lesson) affects one pass. The loop carries on with the next element.
- Stopping early (the previous lesson, with
return) ends the whole loop.
Inverting the condition is the standard way to turn a "skip when" rule into code. If a rule says "skip people under 21", the code says "do the work when the age is at least 21". The wording flips, and so does the comparison: "skip when age < 21" becomes "run when age >= 21".
The exercise
The array heights holds 180, 139, 174, 190, 162. Only people at least 170 tall are allowed into the arena, and the program prints their heights.
- Loop over the heights. Write
for (height <- heights). The arrow reads as "for eachheightinheights". - Keep only the tall ones. Add an
ifwhose condition isheight >= 170. Anifwithout anelsedoes nothing when its condition is false, so short people are skipped. - Print inside the
if.println(height)goes between the braces of theif, so it only runs for the qualifying heights.
val heights = Array(180, 139, 174, 190, 162)
for (height <- heights) {
if (height >= 170) {
println(height)
}
}
180
174
190
The heights 139 and 162 are visited but skipped.
Other ways to write the same filter
Scala has shorter forms for this common pattern. A guard can sit right in the loop header:
for (height <- heights if height >= 170) {
println(height)
}
This prints the same three lines. You can also filter first and loop afterwards: heights.filter(_ >= 170) returns a new array holding 180, 174, 190. The explicit if in the body is the form to learn first, because it extends naturally to more complex bodies with several statements.
Gotchas
- Put the work inside the
if. Ifprintln(height)sits after the closing brace of theif, it runs for every height, and the filter has no effect. - Check the boundary. "At least 170" means
>= 170. A person exactly 170 tall qualifies. Writing> 170drops that value. - Don't change the array to skip items. The loop variable is a copy of each element, and an array has a fixed size. Filtering is done by deciding what to do with each element, not by removing it from the array.
- Nothing is skipped in the loop itself. Every element is still visited, so the loop costs the same number of passes with or without the filter.
Key takeaways
- Scala has no
continue; wrap the work in aniffor the items you want to keep. - Turn "skip when X" into "do the work when not X".
- A guard in the loop header,
for (x <- xs if cond), is a compact form of the same idea.
