1. Overview

In this quick tutorial, we’re going to see a few different ways to iterate Kotlin collections by index.

2. Index Only

To iterate any collection in Kotlin with just the collection index, we can use the indices extension property on the given collection:

val colors = listOf("Red", "Green", "Blue")
for (i in colors.indices) {
    println(colors[i])
}

The indices property will return a range of all valid indices in the collection. Of course, this is applicable to all collections, even arrays:

val colorArray = arrayOf("Red", "Green", "Blue")
for (i in colorArray.indices) {
    println(colorArray[i])
}

It’s also possible to use range expressions in Kotlin to achieve the same thing:

for (i in 0 until colors.size) {
    println(colors[i]) 
}

We can even use this compact version:

(0 until colors.size).forEach { println(colors[it]) }

First, we’re creating a range between 0 (inclusive) and the collection size (exclusive). Then we will call the same println() for each index. This approach, however, is a bit less readable compared to the first one. Therefore, it’s recommended to use the indices extension property wherever possible.

3. Index and Value

If we want to iterate based on both indices and values, we can use the forEachIndexed() extension function:

colors.forEachIndexed { i, v -> println("The value for index $i is $v") }

As shown above, we’re iterating with the index and value combination using a lambda. The lambda accepts two parameters: the index as the first parameter and the value as the second one.

Moreover, if we prefer the for expressions, we can use the withIndex() extension function:

for (indexedValue in colors.withIndex()) {
    println("The value for index ${indexedValue.index} is ${indexedValue.value}")
 }

The withIndex() function returns a collection of the IndexedValue data class instances. Since it’s a data class, we can use destructing patterns on it:

for ((i, v) in colors.withIndex()) {
    println("The value for index $i is $v")
}

Using a destructing pattern is more elegant and readable, so it’s the preferred approach here.

Finally, sometimes we may need to filter elements based on their index or value. To do that, we can use the filterIndexed() extension function:

colors.filterIndexed { i, v -> i % 2 == 0 }

Similar to forEachIndexed(), this function also accepts a lambda expression with the same parameters. If we don’t need a parameter, we can omit it via an underscore:

colors.filterIndexed { i, _ -> i % 2 == 0 }

4. Conclusion

In this short tutorial, we got familiar with different ways to iterate or filter any collection with an index or with index-value combinations. Also, we had a quick refresher on some elegant Kotlin concepts such as destructing patterns.

As usual, all the examples are available over on GitHub.