Как получить текущий индекс элемента в цикле forEach в Kotlin?
Использование withIndex() — стандартное решение
Самый простой и идиоматичный способ получить индекс в Kotlin — использовать функцию-расширение withIndex(). Она возвращает коллекцию объектов IndexedValue, каждый из которых содержит index и value:
val tasks = listOf("Купить хлеб", "Помыть посуду", "Сделать уроки")
tasks.withIndex().forEach { (index, task) ->
println("$index: $task")
}
// Вывод:
// 0: Купить хлеб
// 1: Помыть посуду
// 2: Сделать уроки
Обратите внимание на деструктуризацию: (index, task) — это удобный способ сразу разложить IndexedValue на составляющие. Если вам не нравится синтаксис, можно написать явно:
tasks.withIndex().forEach { indexedValue ->
println("${indexedValue.index}: ${indexedValue.value}")
}
Альтернатива: forEachIndexed()
Для тех, кто предпочитает более прямой вызов, существует встроенная функция forEachIndexed. Она принимает лямбду с двумя параметрами: индекс и элемент:
tasks.forEachIndexed { index, task ->
println("$index: $task")
}
Это эквивалентно предыдущему решению, но короче. Выбирайте то, что вам удобнее.
Почему не стоит использовать внешний счётчик?
Ваш вариант с var index = 0 работает, но имеет два недостатка:
- Проблемы с параллельной обработкой. Если вы замените
forEachнаparallelStreamилиforEachна коллекции из Java, mutable переменная вызовет состояние гонки. - Неидиоматичность. В Kotlin принято избегать мутабельных переменных там, где можно обойтись без них. Это делает код чище и безопаснее.
Если нужен только индекс (без элемента)
Иногда требуется только индекс, например, для обновления элементов. Используйте indices:
for (i in tasks.indices) {
println("Индекс $i")
}
Или forEachIndexed с игнорированием элемента:
tasks.forEachIndexed { index, _ ->
println("Индекс $index")
}
Для массивов
Все те же функции работают и с массивами:
val array = arrayOf("A", "B", "C")
array.withIndex().forEach { (i, v) -> println("$i: $v") }
array.forEachIndexed { i, v -> println("$i: $v") }
Итог: для получения индекса в forEach используйте withIndex() или forEachIndexed. Это стандартные, безопасные и читаемые решения, принятые в Kotlin-сообществе.
Старый добрый for с range
Если вам привычнее классический цикл или нужно больше контроля (например, шаг, обратный порядок), можно использовать for с диапазоном индексов:
val tasks = listOf("Купить хлеб", "Помыть посуду", "Сделать уроки")
for (i in tasks.indices) {
println("$i: ${tasks[i]}")
}
Здесь indices возвращает диапазон 0..size-1. Это работает и для массивов. Если нужен доступ к элементу через геттер, используйте tasks[i].
Когда это может быть удобнее?
- Когда нужно модифицировать элементы по индексу:
tasks[i] = tasks[i].uppercase(). - Когда требуется обратный проход:
for (i in tasks.lastIndex downTo 0). - Когда нужно пропускать элементы:
for (i in 0 until tasks.size step 2).
Недостаток — код чуть длиннее, чем forEachIndexed. Но для сложных сценариев это предпочтительнее. Выбирайте инструмент под задачу.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги