How does mapIndexed work, and how does it relate to withIndex() and mapIndexedNotNull?
answer
- mapIndexed transform = (index, value) -> R, 0-based
- still 1-to-1 like map
- withIndex() -> IndexedValue, destructure (i, v)
- mapIndexedNotNull = indexed map + drop nulls
- family: forEachIndexed, filterIndexed, mapIndexedTo
basics
~10 smapIndexed transforms each element while also giving you its position number, starting at 0. So you can use both the index and the value to build each result.
solid answer
~40 smapIndexed takes a transform `(index: Int, value: T) -> R` and returns a List<R>, passing each element's zero-based position alongside the value. It's the indexed counterpart of map. A close alternative is `withIndex()`, which wraps each element in an IndexedValue(index, value) so you can destructure it in a regular map/loop: `withIndex().map { (i, v) -> ... }`. mapIndexed is more direct when you need the index in the transform. mapIndexedNotNull combines indexing with null-dropping: the transform returns R? and null results are discarded. There are also forEachIndexed and filterIndexed in the same indexed family, plus the *To variant mapIndexedTo. The index reflects iteration order on an ordered collection.
code
kotlin · 3 linesval rows = listOf("Alice", "Bob")
val numbered = rows.mapIndexed { i, name -> "${i + 1}. $name" }
// ["1. Alice", "2. Bob"]go deeper
Knows mapIndexed gives a 0-based index plus value and returns one result per element.
Relates it to withIndex()/IndexedValue and to mapIndexedNotNull for null-dropping.
Chooses between mapIndexed and withIndex based on whether the index is needed across operators, and knows the *To/Indexed family.
Notes index semantics differ for ordered vs unordered collections and reasons about readability/allocation when picking among the indexed variants.
## mapIndexed `mapIndexed` is `map` plus the element's **zero-based index**: ```kotlin public inline fun <T, R> Iterable<T>.mapIndexed( transform: (index: Int, value: T) -> R ): List<R> ``` The transform receives `(index, value)` and you return one result per element (still 1-to-1, like `map`). ```kotlin val letters = listOf("a", "b", "c") val labeled = letters.mapIndexed { i, s -> "$i:$s" } // [0:a, 1:b, 2:c] ``` ## withIndex() `withIndex()` returns an `Iterable<IndexedValue<T>>`, where `IndexedValue` is a small data-class-like holder of `(index, value)`. You then use a normal operator and **destructure**: ```kotlin val labeled2 = letters.withIndex().map { (i, s) -> "$i:$s" } for ((i, s) in letters.withIndex()) println("$i $s") // also great in loops ``` Use `withIndex()` when you want indices available across several operators or in a `for` loop; use `mapIndexed` when you just need the index inside one transform. ## mapIndexedNotNull Combines indexing with null-dropping — the transform returns `R?` and `null` results are removed: ```kotlin val everyOther = listOf("a", "b", "c", "d") .mapIndexedNotNull { i, s -> if (i % 2 == 0) s else null } // [a, c] ``` Equivalent in spirit to `mapIndexed { ... }.filterNotNull()` but in one pass with a non-null result type. ## The indexed family - `forEachIndexed` — side effects with index. - `filterIndexed` — predicate gets `(index, value)`. - `mapIndexedNotNull`, `mapIndexedTo`, `mapIndexedNotNullTo` — null-dropping / destination variants. ## Note The index is the **iteration position** (0-based), meaningful for ordered collections (List). For unordered collections it still increments but reflects iteration order, not a semantic position.
- When would you prefer withIndex() over mapIndexed?When you need the index across multiple chained operators or in a for-loop with destructuring, rather than only inside a single transform lambda. withIndex() exposes IndexedValue you can carry along.
- Is the index 0-based or 1-based, and is it reliable for a HashSet?It is 0-based. It is the iteration position, so for an ordered List it is meaningful; for an unordered collection like HashSet it merely reflects iteration order and has no stable semantic meaning.
saying these in an interview costs you the question
- Claiming the index is 1-based
- Saying mapIndexed can change the result size (it is 1-to-1)
- Not knowing withIndex() returns IndexedValue
- Confusing mapIndexed with flatMap
- Thinking mapIndexedNotNull keeps nulls