Arrays are mutable
A Scala Array has a fixed length, but its elements can be replaced at any time. To change one, write the index in parentheses on the left side of an assignment:
val ourArray = Array(50, 40, 30)
ourArray(0) = 15
ourArray(1) = -1
// ourArray is now Array(15, -1, 30)
The array was declared with val, and the assignments still work. val stops you from pointing ourArray at a different array, as in ourArray = Array(1), which fails with Reassignment to val. It doesn't freeze the elements inside the array.
This differs from strings. A String is immutable, so you can't write s(0) = 'x'. An array is a container whose slots you can overwrite.
What ourArray(0) = 15 really does
An assignment to an indexed value is rewritten by the compiler as a call to the array's update method: ourArray.update(0, 15). Reading, by contrast, calls apply. Collections that have an update method accept this syntax, and those without it don't. An immutable List has none, so L(0) = 5 on a list gives the error value update is not a member of List[Int].
Compound assignment
To change an element based on its current value, combine the index with an operator such as +=:
val ages = Array(14, 32, 50, 21)
ages(1) += 5
Scala expands ages(1) += 5 into ages(1) = ages(1) + 5. The element at index 1 was 32, and now it is 37. The rest are unchanged, so the array holds 14, 37, 50, 21.
The exercise
The lesson starts with:
val fruits = Array("mango", "kiwi", "grapefruit")
val ages = Array(14, 32, 50, 21)
- Change the first fruit to
"apple". The first item is at index 0, so assign tofruits(0). - Add 5 to the second age. The second item is at index 1. Use
ages(1) += 5.
val fruits = Array("mango", "kiwi", "grapefruit")
val ages = Array(14, 32, 50, 21)
fruits(0) = "apple"
ages(1) += 5
Afterwards, fruits holds apple, kiwi, grapefruit and ages holds 14, 37, 50, 21.
Updating many elements
A loop over the indexes can change every element. This one doubles each age:
for (i <- 0 until ages.length) {
ages(i) = ages(i) * 2
}
Starting from 14, 32, 50, 21 the array becomes 28, 64, 100, 42. The index form is needed here, because a loop like for (age <- ages) gives you copies of the numbers, and assigning to the loop variable would not touch the array.
Swapping two elements follows the same idea. Save one value in a temporary variable first, then overwrite both slots: val t = ages(0), then ages(0) = ages(3), then ages(3) = t. On the doubled array this gives 42, 64, 100, 28.
Gotchas
- The type is fixed. An
Array[Int]only accepts integers, soages(0) = "x"is a compile error. - Invalid indexes. Assigning to an index outside the array, such as
ages(4) = 1, throws anArrayIndexOutOfBoundsException. An array can't grow to make room. - Shared arrays. Assigning an array to another variable doesn't copy it. With
val alias = ages, the statementalias(0) = 9also changesages(0), because both names refer to one array. - Brackets. The assignment is
fruits(0) = "apple". Square brackets don't compile here either.
Seeing the result
A plain Array doesn't print its contents with println, so to check your change, turn it into text first. println(ages.mkString(", ")) prints 14, 37, 50, 21 after the exercise, and println(fruits.mkString(", ")) prints apple, kiwi, grapefruit. Calling .toList also works, and prints List(14, 37, 50, 21).
Key takeaways
- Replace an element with
array(i) = value. - Use
array(i) += nto change an element relative to its current value. valfixes the variable, not the array's contents.
