skip to content

You need both the index and the element while iterating a list. Show the idiomatic Kotlin way and explain what withIndex() returns and how it compares to indices.

level: middleimportance: should knowfreq 55%

answer

  1. withIndex() -> IndexedValue(index, value)
  2. destructure (index, value) in for
  3. indices = 0 until size
  4. forEachIndexed is the lambda form
  5. avoid list[i] in a loop (extra lookup)

basics

~10 s

Use withIndex() in the for loop. It gives you a pair of (position, value) for each item, so you can read both at once without manually tracking a counter.

solid answer

~40 s

The idiomatic way is `for ((index, value) in list.withIndex()) { ... }`. `withIndex()` returns an `Iterable<IndexedValue<T>>`; each `IndexedValue` has `index: Int` and `value: T`, and you destructure it via component1()/component2(). This avoids a manual counter and avoids re-indexing with `list[i]`. Alternatives: `for (i in list.indices)` gives just the index range (`0 until size`) when you only need positions; `list.forEachIndexed { i, v -> }` is the lambda equivalent. Prefer `withIndex()`/`forEachIndexed` over `for (i in indices) { val v = list[i] }` because the latter does an extra index lookup each iteration and reads worse. `withIndex()` works on any `Iterable`/`Sequence`/array/CharSequence, not just lists.

code

kotlin · 8 lines
kotlin
val items = listOf("a", "b", "c")
for ((i, v) in items.withIndex()) println("$i=$v") // 0=a 1=b 2=c

// index only
for (i in items.indices) print(i)                  // 012

// lambda form
items.forEachIndexed { i, v -> println("$i:$v") }

go deeper

for a junior

Uses withIndex() or forEachIndexed to get index and value instead of a manual counter.

for a middle

Knows withIndex() yields IndexedValue and chooses indices vs withIndex appropriately.

for a senior

Explains laziness of withIndex(), data-class destructuring, and the O(n^2) trap of list[i] on non-random-access lists.

for a principal

Weighs withIndex/forEachIndexed/indices for readability, allocation, and access cost across collection types and sequences.

## The need Sometimes you want the position alongside the element. Manually tracking `var i = 0; i++` is error-prone. Kotlin gives cleaner tools. ## withIndex() ```kotlin for ((index, value) in list.withIndex()) { println("$index -> $value") } ``` - `withIndex()` is an extension on `Iterable`, `Sequence`, arrays, and `CharSequence`. - It returns an `Iterable<IndexedValue<T>>` (lazy — it wraps the source iterator, doesn't copy). - Each `IndexedValue<T>` is a data class with `index: Int` and `value: T`. Because it's a data class it provides `component1()`/`component2()`, enabling the `(index, value)` **destructuring** in the loop. ## indices When you only need positions: ```kotlin for (i in list.indices) { /* i in 0 until list.size */ } ``` `indices` is an extension returning the `IntRange` `0 until size`. Use it for index-only logic (e.g. swapping `list[i]` and `list[j]`). ## forEachIndexed The functional equivalent: ```kotlin list.forEachIndexed { i, v -> println("$i: $v") } ``` Use this in lambda-style pipelines; use `withIndex()` in a `for` loop when you want `break`/`continue`. ## What to avoid ```kotlin for (i in list.indices) { val v = list[i] } // extra lookup, noisier ``` For a `LinkedList`, `list[i]` is O(n), making the whole loop O(n^2) — `withIndex()` avoids that by walking the iterator once. ## Summary - Need both -> `withIndex()` (loop) or `forEachIndexed` (lambda). - Need only positions -> `indices`. - Avoid manual counters and repeated `list[i]` lookups.

  • What type does withIndex() yield per iteration?
    An IndexedValue<T> data class with .index: Int and .value: T, which destructures into (index, value).
  • When would you use indices instead of withIndex()?
    When you only need positions or need to access multiple indices at once (e.g. swapping list[i] and list[i+1]).

saying these in an interview costs you the question

  • Manually maintaining var i = 0; i++ inside the loop
  • Using for (i in indices) { list[i] } when both are needed (extra lookups)
  • Thinking withIndex() copies the collection
  • Confusing withIndex() (pairs) with indices (just the range)

context