When you need the index
Most array loops in Scala use the elements directly: for (x <- array) gives you each value in turn. That loop doesn't tell you where in the array you are. Sometimes the position matters. You may want to print "item number 3", compare each element with the one before it, change elements in place, or return the position of a match. For those jobs you loop over the indices, the positions themselves, and read each element with its index.
Indices and ranges
An array of n elements has the indices 0 through n - 1. The first element is at index 0 and the last is at index size - 1. Scala reads an element with parentheses, meals(2), not with square brackets.
Scala builds the sequence of indices with a range. There are two range operators, and the difference is whether the upper end is included:
0 until nstops beforen: 0, 1, ...,n - 1. This is the range of valid indices.0 to nincludesn: 0, 1, ...,n. As an index range it is one step too long.
An array also provides its index range ready-made as indices, so for (i <- meals.indices) and for (i <- 0 until meals.size) visit the same positions. The property size gives the number of elements, and length gives the same number.
An example
val meals = Array("pancakes", "pasta", "pizza", "avocado")
for (i <- meals.indices) {
println("Meal number " + (i + 1) + " is " + meals(i) + ".")
}
The output is:
Meal number 1 is pancakes.
Meal number 2 is pasta.
Meal number 3 is pizza.
Meal number 4 is avocado.
Indices start at 0, but people count from 1. That is why the code prints i + 1. The parentheses matter: "Day " + x + 1 with x = 5 builds the text Day 51, because each + appends text from left to right. "Day " + (x + 1) adds first and gives Day 6.
The exercise: the temperature on each day
The lesson gives an array temperatures and asks for one line per day, in the form On day 1 the temperature is 10. The two steps are:
- Loop over the indices. Use a variable
iand the range0 until temperatures.size. Theuntilkeepsifrom reachingtemperatures.size, which is one past the last valid index. - Print the line inside the loop with an
s"..."string. Thesin front of the quotes turns on string interpolation: a${...}inside the string is replaced by the value of the expression in the braces. The day is${i + 1}and the temperature is${temperatures(i)}.
val temperatures = Array(10, 60, -5, 32)
for (i <- 0 until temperatures.size) {
println(s"On day ${i + 1} the temperature is ${temperatures(i)}.")
}
The output is:
On day 1 the temperature is 10.
On day 2 the temperature is 60.
On day 3 the temperature is -5.
On day 4 the temperature is 32.
More things the index lets you do
With the index you can write to the array, since arrays in Scala are mutable. temperatures(i) = temperatures(i) * 2 replaces the element at position i. You can also walk backwards with temperatures.indices.reverse, skip positions with 0 until temperatures.size by 2, or compare neighbours. A loop that starts at 1 can read the element before the current one:
for (i <- 1 until temperatures.size) {
println(temperatures(i) - temperatures(i - 1))
}
For Array(10, 60, -5, 32) this prints 50, -65 and 37. It starts at 1 because index 0 has no previous element.
Common mistakes
- Using
toinstead ofuntil. The loopfor (i <- 0 to temperatures.size)runs once too often. On the last passtemperatures(4)asks for an element that doesn't exist, and the program stops withjava.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4. - Starting at 1. That skips the first element.
- Printing
iwhere you meani + 1. The first day would be "day 0". - Square brackets.
temperatures[i]is not how Scala reads an element. Usetemperatures(i). - An empty array.
0 until 0is an empty range, so the loop body never runs and nothing is printed.
Key takeaways
- The valid indices of an array are 0 through
size - 1. 0 until temperatures.sizeandtemperatures.indicesproduce exactly those indices.- Use
towhen you want the upper end included anduntilwhen you don't. - Read an element with
array(i)and write one witharray(i) = value. - Loop over the indices when the position matters, and over the elements when it doesn't.
