Start learning free

LESSON 98 OF 414 · ARRAYS I

Updating Elements in Scala: ArrayBuffer Index Assignment

Lesson Read the full explanation

The entries of an ArrayBuffer are mutable and can be changed freely, using indices and index assignment:

Index assignment takes an index and a value and changes the element placed at that index with the argument value:

val numbers = scala.collection.mutable.ArrayBuffer(50, 40, 30)

numbers(0) = 15
numbers(2) = -1

// numbers is now [15, 40, -1]

Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    SCALA · ARRAYS I

    Updating Elements in Scala, explained

    Changing an element by index

    The entries of an ArrayBuffer can be replaced. You write the index in parentheses on the left side of an assignment, and the value on the right:

    val numbers = scala.collection.mutable.ArrayBuffer(50, 40, 30)
    numbers(0) = 15
    numbers(2) = -1
    // numbers is now ArrayBuffer(15, 40, -1)
    

    The element at the given index is replaced, and the buffer keeps its size and the order of the other elements. Only the slots you assign to change.

    val and mutation

    The buffer above is declared with val, and the assignments are allowed. A val means the name numbers always refers to the same buffer. It says nothing about the buffer's contents. Writing numbers = ArrayBuffer(1) is the thing that fails, with Reassignment to val.

    What happens behind the syntax

    The compiler turns numbers(0) = 15 into the call numbers.update(0, 15). Reading numbers(0) calls apply instead. Types that define update allow index assignment, and types that don't, don't. A List is immutable and has no update, so list(0) = 5 fails to compile. For a list you ask for a modified copy: list.updated(0, 5) returns a new list and leaves the original alone.

    The exercise

    The lesson starts with two buffers:

    val fruits = scala.collection.mutable.ArrayBuffer("mango", "kiwi", "grapefruit")
    val ages = scala.collection.mutable.ArrayBuffer(14, 32, 50, 21)
    
    1. Change the first fruit to "apple". The first item is at index 0, so write fruits(0) = "apple".
    2. Add 5 to the second age. The second item is at index 1. Read it, add 5 and store the result back: ages(1) = ages(1) + 5. The right side is computed first, from the old value 32, so the new value is 37.
    val fruits = scala.collection.mutable.ArrayBuffer("mango", "kiwi", "grapefruit")
    val ages = scala.collection.mutable.ArrayBuffer(14, 32, 50, 21)
    fruits(0) = "apple"
    ages(1) = ages(1) + 5
    

    Afterwards, fruits is ArrayBuffer(apple, kiwi, grapefruit) and ages is ArrayBuffer(14, 37, 50, 21). The shorter form ages(1) += 5 does the same thing.

    Updating many elements

    To change every element, loop over the indexes. The method indices gives the valid ones, from 0 to the size minus one:

    for (i <- ages.indices) {
        ages(i) += 1
    }
    

    With the ages as they are after the exercise, 14, 37, 50, 21, the buffer becomes 15, 38, 51, 22. Looping over the values with for (age <- ages) reads them but can't store anything back, because age is a copy of each number, so use the index when you want to write.

    Two names can also refer to one buffer. After val ref = ages, the assignment ref(0) = 9 changes ages(0) as well, because no copy is made.

    Gotchas

    • Replacing is not inserting. Assigning to an index overwrites the element there. To add a new element at the end, use += on the buffer itself, as in ages += 99, which makes the size 5.
    • The index must already exist. Assigning to an index at or past the size throws an IndexOutOfBoundsException. The buffer does not grow to fit.
    • Element type. The buffer's type is inferred from its initial values, so fruits only accepts strings and ages only integers.
    • Parentheses. The index goes in parentheses, never brackets.

    Key takeaways

    • buffer(i) = value replaces the element at index i.
    • To update from the old value, read it on the right side: ages(1) = ages(1) + 5.
    • val keeps the variable pointing at one buffer, and the buffer's elements can still change.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free