Глиф Учебники

Как перебрать список с индексом

Справочник · Kotlin · 1 минута чтения

Kotlin
fun main() {
    val colors = listOf("red", "green", "blue")

    for ((index, color) in colors.withIndex()) {
        println("$index: $color")
    }

    colors.forEachIndexed { i, c ->
        println("${i + 1}. $c")
    }

    for (i in colors.indices) {
        println("${colors[i]} has ${colors[i].length} letters")
    }
}
Вывод
0: red
1: green
2: blue
1. red
2. green
3. blue
red has 3 letters
green has 5 letters
blue has 4 letters
СпособКогда удобен
for ((i, x) in list.withIndex())обычный цикл, нужны и номер, и значение; работают break и continue
list.forEachIndexed { i, x -> ... }короткое действие с каждым элементом
for (i in list.indices)нужны соседние элементы (list[i - 1], list[i + 1]) или замена по номеру

Номера начинаются с нуля. Для нумерации «по-человечески» выводите i + 1.

withIndex() превращает список в последовательность пар «номер — значение», а запись (index, color) сразу раскладывает каждую пару по двум переменным. Имена переменных можно выбрать любые: (i, c), (n, item).

Найти номер элемента

Если нужен не перебор, а номер одного элемента, цикл не нужен:

Kotlin
fun main() {
    val colors = listOf("red", "green", "blue")
    println(colors.indexOf("blue"))
    println(colors.indexOf("black"))
    println(colors.indexOfFirst { it.length > 3 })
}
Вывод
2
-1
1

indexOf возвращает номер первого такого элемента или -1, если его нет. indexOfFirst { ... } — номер первого элемента, для которого условие верно: здесь это green, первое слово длиннее трёх букв.

Только значения

Если номер не нужен, проще без него:

Kotlin
fun main() {
    val colors = listOf("red", "green", "blue")
    for (c in colors) {
        println(c)
    }
}
Вывод
red
green
blue

В обратном порядке

Kotlin
fun main() {
    val nums = listOf(10, 20, 30)
    for (i in nums.indices.reversed()) {
        println("$i: ${nums[i]}")
    }
    for (x in nums.reversed()) {
        println(x)
    }
}
Вывод
2: 30
1: 20
0: 10
30
20
10

То же, что nums.indices.reversed(), — nums.lastIndex downTo 0; lastIndex — номер последнего элемента, size - 1.

Изменить элементы по номеру

В изменяемом списке элемент можно заменить через номер:

Kotlin
fun main() {
    val prices = mutableListOf(100, 250, 80)
    for (i in prices.indices) {
        prices[i] = prices[i] * 2
    }
    println(prices)
}
Вывод
[200, 500, 160]

Если нужен новый список, а не изменение старого, короче mapIndexed: list.mapIndexed { i, x -> x * i } возвращает новый список, исходный не меняется.

Частая ошибка: 0..list.size

Kotlin
fun main() {
    val list = listOf(1, 2, 3)
    for (i in 0..list.size) {
        println(list[i])
    }
}

0..list.size включает и size — здесь 3, а последний номер — 2. Программа выведет три числа и упадёт с ошибкой IndexOutOfBoundsException (или ArrayIndexOutOfBoundsException). Правильно — list.indices, 0 until list.size или 0..<list.size.

Перебор for (x in list) нельзя совмещать с удалением из того же списка: при list.remove(x) внутри такого цикла программа обычно падает с ConcurrentModificationException. Удаляйте элементы по условию одной командой: list.removeAll { it < 0 } — или соберите новый список через filter.