Replacing an element
The elements of a MutableList can be changed. Use the index operator [] on the left of an assignment, with the index in the brackets and the new value on the right. Kotlin turns that into a call to the list's set method, so numbers[0] = 15 and numbers.set(0, 15) do the same thing.
val numbers = mutableListOf(50, 40, 30)
numbers[0] = 15
numbers[2] = -1
println(numbers)
[15, 40, -1]
Only the elements at indices 0 and 2 changed. The size is still 3, and the element at index 1 is still 40.
Read-only lists
This only works on a mutable list. A list made with listOf is read-only, and listOf(1, 2)[0] = 5 doesn't compile: the compiler reports that there is no set operator method providing array access. That is why the lesson builds its lists with mutableListOf.
Using the old value
To change an element based on its current value, read it, compute the new value and store it in the same place:
val scores = mutableListOf(10, 20, 30)
scores[1] = scores[1] + 5
println(scores)
[10, 25, 30]
The right side is evaluated first, using the old value 20, and the result 25 is then stored at index 1. Kotlin also accepts the shorter scores[1] += 5, which means the same.
Replacing versus adding
Assignment by index and add do different jobs. Assignment replaces an element that is already there: the index must be valid, and the size stays the same. add puts a new element at the end and makes the list one longer. Mixing them up is a common beginner error, such as writing ages[4] = 7 on a four-item list when ages.add(7) was meant.
Why val still works
Changing an element isn't the same as reassigning the variable. The statement fruits[0] = "apple" changes what the list holds, while fruits = mutableListOf() would try to point the variable somewhere else, which a val forbids. That is why a val list can be updated freely.
The exercise
The starter code:
val fruits = mutableListOf("mango", "kiwi", "grapefruit")
val ages = mutableListOf(14, 32, 50, 21)
- Replace the first fruit. Assign
"apple"to index 0. The variablefruitsis aval, but that only stops it from being pointed at another list, so changing an element is fine. - Add 5 to the second age. The second item is at index 1. Assign
ages[1] + 5back toages[1], turning 32 into 37.
val fruits = mutableListOf("mango", "kiwi", "grapefruit")
val ages = mutableListOf(14, 32, 50, 21)
fruits[0] = "apple"
ages[1] = ages[1] + 5
Nothing is printed. With println(fruits) and println(ages) added, the output is [apple, kiwi, grapefruit] and [14, 37, 50, 21].
Compound forms
The shorthand operators work on list elements as well: ages[1] += 5 reads the element, adds 5 and stores the result at the same index, and -=, *= and /= follow the same pattern. The long form in the exercise, ages[1] = ages[1] + 5, and the short form give the same list.
Common mistakes
- Using the wrong index. Indexing starts at 0, so
fruits[1] = "apple"replaceskiwi, notmango. - Assigning at the end.
ages[4] = 1on a four-item list throwsIndexOutOfBoundsException. Assigning to an index replaces an element and never adds one. Useaddto append. - Writing
ages[1] + 5alone. That computes 37 and throws the result away. Without the assignment, the list is unchanged. - Mixing types. A
MutableList<Int>doesn't accept a string, soages[0] = "old"doesn't compile.
The set method and a loop
Calling set directly has one difference from the bracket form: it returns the value that used to be stored at that index.
val nums = mutableListOf(50, 40, 30)
val old = nums.set(0, 15)
println(old)
println(nums)
for (i in nums.indices) {
nums[i] += 1
}
println(nums)
50
[15, 40, 30]
[16, 41, 31]
The loop shows how assignment by index updates every element in place. Updating the list inside the loop is safe here because the size never changes; adding or removing items while looping over the list is a different matter.
Copies are separate
Assigning a list to another variable gives two names for one list. To change a copy without touching the original, make the copy with toMutableList():
val copy = nums.toMutableList()
copy[0] = 0
println(nums)
println(copy)
[16, 41, 31]
[0, 41, 31]
Key takeaways
list[i] = valuereplaces the element at indexiand callssetfor you.- It works on a
MutableList, not on a read-onlyList. - The size doesn't change when you replace an element.