Reading an element of a list
A Kotlin list keeps its elements in order, and each has an index starting at 0. To read the element at an index, put the index in square brackets after the list's name. The brackets are shorthand for the list's get method, so list[1] and list.get(1) do the same thing. Square brackets are the form Kotlin programmers normally write.
val array = mutableListOf(50, 60, 70)
println(array[0])
val data = array[1]
println(data)
println(array.get(2))
50
60
70
The first element is at index 0, so a list with 3 elements has valid indices 0, 1 and 2. Reading any other index throws an IndexOutOfBoundsException.
Using the value
The result of array[1] has the list's element type. For a MutableList<Int> it is an Int, which you can store in a variable, as data does above, or use directly in an expression.
Why counting starts at zero
An index is best read as an offset: how many steps you are from the start of the list. The first element is zero steps from the start, so it is at index 0, and the last element of a list with n items is at index n - 1. Thinking of the index as a distance, rather than as a place in a queue, makes off-by-one mistakes less likely.
Index and element types
The index is always an Int. The element has the type the list was declared with, so the compiler knows what you get back before the program runs. In a MutableList<String> every indexed read is a String, and storing one in an Int variable doesn't compile.
The exercise
The starter code creates two lists:
val fruits = mutableListOf("mango", "kiwi", "grapefruit")
val ages = mutableListOf(14, 32, 50, 21)
- Print the second fruit. Use index 1. It prints
kiwi. - Print the sum of the first three ages. Put the three indexed values in one expression inside
println. Kotlin works out 14 + 32 + 50 first and prints96. - Print the last age minus the first. There are four numbers, so the last index is 3, giving 21 - 14 and the output
7.
val fruits = mutableListOf("mango", "kiwi", "grapefruit")
val ages = mutableListOf(14, 32, 50, 21)
println(fruits[1])
println(ages[0] + ages[1] + ages[2])
println(ages[3] - ages[0])
kiwi
96
7
Reading never changes the list
Reading an element leaves the list exactly as it was, so you can read the same index as often as you like. The one thing to watch is that the index is valid. If it comes from a calculation, such as ages.size - 1, make sure the calculation can't produce a value below 0 or at least the size. Kotlin also offers getOrNull(index), which returns null instead of throwing when the index is outside the list.
Indexing is also quick: reading an element of an ArrayList takes the same time whether it is at index 0 or at index 100,000, because the list is stored as a block of consecutive slots.
Common mistakes
- Counting from 1. The second item is at index 1.
fruits[2]is the third,grapefruit. - Reading past the end. In a list of 4 items,
ages[4]throwsIndexOutOfBoundsException. In general the last index is the size minus one. - Negative indexes. Kotlin doesn't count from the end with negative numbers.
ages[-1]throws; useages.last()orages[ages.size - 1]. - Printing the whole list.
println(ages)prints all of it:[14, 32, 50, 21]. Add the index when you need one element.
Visiting every element
Indexing combines well with a loop. A list's indices property is the range of valid positions, so a loop over it never goes out of bounds:
val fruits = mutableListOf("mango", "kiwi")
for (i in fruits.indices) {
println("$i: ${fruits[i]}")
}
println(fruits[1].uppercase())
println(fruits.first())
0: mango
1: kiwi
KIWI
mango
The element fruits[1] is a String, so string functions such as uppercase() work on it. The function first() is a readable shortcut for fruits[0], and last() is the one for the final element.
Key takeaways
- List indices start at 0 and end at size - 1.
list[i]is shorthand forlist.get(i).- An indexed element is an ordinary value, so it works in arithmetic and in
println.