What do the standard library functions map and filter do on a Kotlin collection, and what does each return?
answer
- map = 1-to-1 transform, same size
- filter = keep where predicate true, size shrinks
- filterNot = inverse of filter
- both return a NEW List, source untouched
- eager on Iterable, lazy via asSequence()
basics
~20 smap turns each element into something else and gives back a new list of the results. filter keeps only the elements that match a condition and gives back a new list. Both leave the original list unchanged.
solid answer
~40 smap applies a transform lambda to every element and returns a new List with the transformed values, preserving order and size. filter applies a predicate (a function returning Boolean) and returns a new List containing only elements for which it is true; size may shrink. Both are extension functions on Iterable, are non-mutating (the receiver is untouched), and eagerly produce a fresh ArrayList. The lambda's last expression is the result for map; filterNot is the inverse of filter. For nullable results use mapNotNull; for an index use mapIndexed. On a List the static return type is List<R>, but the concrete object is a new ArrayList.
code
kotlin · 4 linesval xs = listOf(1, 2, 3, 4, 5)
val doubledEvens = xs.filter { it % 2 == 0 }.map { it * 2 } // [4, 8]
println(xs) // [1, 2, 3, 4, 5] -- unchanged
println(doubledEvens) // [4, 8]go deeper
States map transforms each element and filter keeps matching ones, both returning a new list without mutating the source.
Adds that results are eager ArrayLists, size rules (map 1-to-1, filter shrinks), and mentions filterNot plus asSequence for laziness.
Discusses intermediate-list allocation in chains, read-only return type vs concrete ArrayList, and when to switch to sequences.
Frames eager-vs-lazy trade-offs at scale, API design of returning read-only List interfaces, and predictable allocation behaviour for hot paths.
## What these are `map` and `filter` are **extension functions** on `Iterable<T>` (and `Array`, `Sequence`, `Map`, etc.) from the Kotlin standard library. An *extension function* is a function you call with dot-syntax on a receiver as if it were a member. Both are **transformation operators**: they read the source collection and build a brand-new collection. Neither mutates the receiver. ## map `map` takes a **transform lambda** `(T) -> R` and returns a `List<R>` whose i-th element is the transform applied to the i-th source element. Order and **size are preserved** (N in, N out). ```kotlin val names = listOf("ann", "bob") val lengths: List<Int> = names.map { it.length } // [3, 3] ``` Here `it` is the implicit single parameter and the lambda's **last expression** is the produced value. ## filter `filter` takes a **predicate** `(T) -> Boolean` and returns a `List<T>` containing only elements for which the predicate is `true`. Size may shrink (0..N out); element type is unchanged. ```kotlin val evens = listOf(1, 2, 3, 4).filter { it % 2 == 0 } // [2, 4] ``` `filterNot { ... }` keeps elements where the predicate is **false** (the inverse). ## Key properties - **Eager**: on a `List`/`Iterable` the result is computed immediately into a new `ArrayList`. (Wrapping with `.asSequence()` makes it lazy.) - **Non-mutating**: the source is never changed; you get a new object. - **Return type**: declared as `List<R>`/`List<T>` (read-only interface), backed by a mutable `ArrayList` instance. - Chaining `xs.filter { ... }.map { ... }` creates an **intermediate list** for each step. ## Related operators in this family `mapNotNull` (drops nulls the transform returns), `mapIndexed` (gives `(index, value)`), `filterNotNull`, `filterIsInstance<T>()`, and `flatMap`.
- If you chain filter then map on a large list, how many intermediate collections are created and how do you avoid them?Each eager step allocates one new list, so filter-then-map creates one intermediate list plus the final list. Use asSequence() to fuse the operations and avoid intermediates.
- Does map ever change the collection's size?No. map is strictly 1-to-1, so output size equals input size. To change size you need filter, mapNotNull, or flatMap.
map is repainting every car a new colour; filter is a bouncer letting only some cars through. Neither alters the original lot.
saying these in an interview costs you the question
- Saying map or filter mutates the original list
- Claiming map can change the number of elements
- Thinking the result is the same object / aliased to the source
- Saying map and filter are lazy on a plain List (they are eager)
- Confusing filter (keeps true) with filterNot (keeps false)