skip to content

Collection Operations

The extension-function toolbox over Iterable: transforming, aggregating, grouping, windowing, ordering, and searching. Interviewers often just hand you a data-shaping task and watch which operators you reach for.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

Given a list of numbers, how do you compute its sum, average, and count in Kotlin, and how do you sum a numeric property of a list of objects?

level: juniorimportance: must knowfreq 75%

answer

  1. sumOf return type follows the lambda type
  2. average() always Double, NaN when empty
  3. maxOrNull/minOrNull are the null-safe ones
  4. sumBy/sumByDouble removed → use sumOf
  5. count{} counts matches, count() = size

basics

~10 s

Use sum() to add numbers, average() for the mean, count() for how many. To sum a field of objects, use sumOf { it.field }, which adds up the chosen value for each item.

solid answer

~40 s

For a List<Int>/List<Double> etc., sum() returns the total and average() returns a Double mean. count() returns the size (and count { predicate } counts matching elements). To total a property, use sumOf { it.price }; its return type follows the lambda — sumOf returning an Int lambda gives Int, a Long lambda gives Long, a Double lambda gives Double. The older sumBy/sumByDouble were deprecated/removed in favor of sumOf. For min/max use maxOrNull()/minOrNull() (nullable) or maxOf { }/minOf { } when you have a non-empty source or a selector. average() on an empty collection returns NaN, while sum() returns the additive identity (0).

code

kotlin · 9 lines
kotlin
val nums = listOf(1, 2, 3, 4)
println(nums.sum())       // 10
println(nums.average())   // 2.5
println(nums.count { it % 2 == 0 }) // 2

val empty = emptyList<Int>()
println(empty.sum())        // 0
println(empty.average())    // NaN
println(empty.maxOrNull())  // null

go deeper

for a junior

Knows sum/average/count exist and can sum a property with sumOf { }.

for a middle

Recalls the empty-collection results (0, NaN, null) and that sumOf's type follows the lambda.

for a senior

Explains why sumOf replaced sumBy and distinguishes maxByOrNull (element) from maxOfOrNull (value).

for a principal

Discusses NaN propagation risks and chooses null-returning vs throwing variants intentionally in API design.

## What aggregation means Aggregation reduces a whole collection down to a single value: a total, a mean, a count. Kotlin's stdlib provides direct extension functions on `Iterable`, `Sequence`, `Array`, and primitive arrays. ## sum / sumOf - `sum()` works on collections of numeric types (`Int`, `Long`, `Double`, `Float`, etc.) and returns the same numeric type (with `Byte`/`Short` widening to `Int`). - `sumOf { selector }` maps each element to a number and totals them. The **return type is inferred from the lambda's type**: a lambda returning `Int` yields `Int`, returning `Long` yields `Long`, returning `Double` yields `Double`. This is how you sum a property: `orders.sumOf { it.amount }`. - `sumBy`/`sumByDouble` are the old names and are gone in modern Kotlin (2.x) — always use `sumOf`. ## average / count - `average()` always returns a `Double` regardless of input numeric type. - On an **empty** collection `average()` returns `Double.NaN`. - `count()` returns the element count as an `Int`. `count { predicate }` counts elements matching a predicate, e.g. `users.count { it.active }`. ## min / max - `maxOrNull()` / `minOrNull()` return the largest/smallest element or `null` if empty (so they are null-safe). - `maxByOrNull { selector }` / `minByOrNull { selector }` return the **element** whose selector value is largest/smallest. - `maxOfOrNull { selector }` / `minOfOrNull { selector }` return the **selector value** itself. - The non-`OrNull` variants (`maxOf`, `minOf`) throw `NoSuchElementException` on an empty source. ```kotlin data class Order(val id: Int, val amount: Double) val orders = listOf(Order(1, 10.0), Order(2, 5.5)) val total: Double = orders.sumOf { it.amount } // 15.5 val avg: Double = orders.map { it.amount }.average() // 7.75 val n: Int = orders.count() // 2 val pricey: Int = orders.count { it.amount > 6 } // 1 val biggest: Order? = orders.maxByOrNull { it.amount } // Order(1, 10.0) ``` ## Empty-collection edge cases (memorize) - `sum()` / `sumOf {}` → 0 (additive identity). - `average()` → `NaN`. - `maxOrNull()` / `minOrNull()` → `null`. - `count()` → 0.

  • What does average() return for an empty list and why is that dangerous?
    Double.NaN. It's dangerous because NaN silently propagates through arithmetic and comparisons (NaN != NaN), so guard with isEmpty() or use a default.
  • Why was sumBy replaced by sumOf?
    sumBy/sumByDouble had fixed return types and overload ambiguity; sumOf infers Int/Long/Double from the lambda, giving one consistent, type-correct API.

sumOf is like a cashier scanning each item and tallying the price you point to, not the item itself.

saying these in an interview costs you the question

  • Claiming average() returns Int or throws on empty (it returns NaN)
  • Using max()/min() and assuming non-null without checking emptiness
  • Still recommending sumBy/sumByDouble
  • Confusing sumOf (sums selector value) with count (counts elements)

context

open as a page

In Kotlin, what is the difference between accessing a list element with `list[i]`, `list.getOrNull(i)`, and `list.getOrElse(i) { default }`? When does each fail or succeed?

level: juniorimportance: must knowfreq 78%

basics

~10 s

list[i] throws an error if the index is out of range. getOrNull(i) returns null instead of throwing. getOrElse(i) { ... } returns a value you compute when the index is out of range.

open as a page

What does the standard-library function `groupBy` do, and what is the exact type of the value it returns?

level: juniorimportance: must knowfreq 80%

basics

~10 s

groupBy sorts items into buckets using a key you choose. It returns a map where each key points to a list of all the items that produced that key.

open as a page

How do you sort a List in Kotlin, and what is the difference between sorted(), sortedBy { }, and sortedDescending()?

level: juniorimportance: must knowfreq 80%

basics

~20 s

Use sorted() to order items from low to high. Use sortedBy { } to sort by a chosen property. Use sortedDescending() for high to low. All three return a new list and leave the original unchanged.

open as a page

What do the standard library functions map and filter do on a Kotlin collection, and what does each return?

level: juniorimportance: must knowfreq 92%

basics

~20 s

map 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.

open as a page

What does zip do on two Kotlin collections, and what determines the size of the result?

level: juniorimportance: must knowfreq 70%

basics

~10 s

zip pairs up elements from two lists by position: first with first, second with second, and so on. The result stops at the shorter list, so its length equals the smaller of the two.

open as a page

Explain all, any, and none on Kotlin collections, including their behavior on an empty collection and the no-argument overloads.

level: middleimportance: must knowfreq 60%

basics

~20 s

all checks every element matches a condition, any checks at least one does, none checks zero do. On an empty list: all is true, any is false, none is true. any() and none() with no argument just test whether the collection has elements.

open as a page

What is the difference between fold and reduce in Kotlin, and when must you choose fold?

level: middleimportance: must knowfreq 70%

basics

~20 s

Both combine elements into one result. fold takes a starting value, so it works on empty collections and can return a different type. reduce uses the first element as the start, so it throws if the collection is empty.

open as a page

Compare `first()`, `firstOrNull()`, `find { }`, and `first { }` in Kotlin. What exceptions can they throw and how do they relate?

level: middleimportance: must knowfreq 80%

basics

~20 s

first() returns the first element but throws if the collection is empty. firstOrNull() returns null instead. first { predicate } returns the first matching element (throws if none); find { predicate } is the same but returns null if none match.

open as a page

Explain the differences between `associate`, `associateBy`, and `associateWith`, including how each handles duplicate keys.

level: middleimportance: must knowfreq 75%

basics

~20 s

All three build a map from a list. associateWith uses elements as keys, associateBy makes elements the values under a chosen key, and associate lets you build both key and value. If two keys collide, the last one wins.

open as a page

Explain Kotlin's comparator DSL: compareBy, thenBy, thenByDescending. How do you sort by multiple keys, and how do ascending/descending mix?

level: middleimportance: must knowfreq 70%

basics

~10 s

compareBy builds a comparator from a property. thenBy adds a tie-breaker used only when the previous keys are equal. Use thenByDescending to reverse one of those keys. Pass the result to sortedWith.

open as a page

Explain flatMap and flatten in Kotlin. How do they differ, and when would you reach for each?

level: middleimportance: must knowfreq 80%

basics

~20 s

flatten takes a list of lists and merges them into one flat list. flatMap first turns each element into a list (or any iterable) and then merges all those into one flat list. Use flatten when you already have nested lists; flatMap when you produce the nested lists yourself.

open as a page

Explain the difference between chunked(n) and windowed(size, step). When do they produce identical results?

level: middleimportance: must knowfreq 60%

basics

~20 s

chunked(n) cuts a list into non-overlapping blocks of n. windowed(size, step) slides a window of size, moving by step each time, so windows can overlap. chunked(n) equals windowed(n, n) but also keeps a smaller final chunk.

open as a page

What does `partition` return, and how is it different from filtering twice or from `groupBy`?

level: juniorimportance: should knowfreq 60%

basics

~20 s

partition splits a collection into two lists based on a true/false test: a Pair where the first list holds items that match and the second holds those that don't. It does it in one pass.

open as a page

How does mapIndexed work, and how does it relate to withIndex() and mapIndexedNotNull?

level: juniorimportance: should knowfreq 55%

basics

~10 s

mapIndexed 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.

open as a page

What do runningFold and runningReduce produce, and how do they relate to scan? Show how you'd build a running balance.

level: middleimportance: should knowfreq 45%

basics

~10 s

Instead of one final value, they return the list of every intermediate accumulator value. runningFold starts with your seed; runningReduce starts with the first element. scan is just another name for runningFold.

open as a page

What are the exact semantics of `single()`, `singleOrNull()`, `single { }`, and `singleOrNull { }` in Kotlin? When would you choose single over first?

level: middleimportance: should knowfreq 58%

basics

~20 s

single() returns the only element and throws if the collection is empty OR has more than one. singleOrNull() returns null in both of those cases. The predicate versions do the same but for elements matching a condition.

open as a page

Describe `chunked`, including its two overloads, the size of the final chunk, and how it differs from `windowed`.

level: middleimportance: should knowfreq 50%

basics

~10 s

chunked breaks a collection into consecutive, non-overlapping pieces of a fixed size. The last piece may be smaller if items run out. A second form lets you transform each piece as it's made.

open as a page

Contrast in-place sort() / sortWith() on MutableList with the sorted() / sortedWith() copying functions. When would you pick each, and what are the return types and receiver constraints?

level: middleimportance: should knowfreq 55%

basics

~20 s

sort() and sortWith() rearrange an existing mutable list and return nothing. sorted() and sortedWith() make a new sorted list and leave the original alone. Use in-place to save memory; use copying when the original must stay intact or the list is read-only.

open as a page

When would you use mapNotNull instead of map, and how does it differ from map followed by filterNotNull?

level: middleimportance: should knowfreq 78%

basics

~20 s

mapNotNull transforms each element but throws away any results that come out null. It is handy when a step can fail or skip values, letting you map and drop nulls in one pass instead of two.

open as a page

What does flatten do, and how does it relate to flatMap? Show both with windowing/chunked output.

level: middleimportance: should knowfreq 40%

basics

~20 s

flatten takes a list of lists and concatenates them into one flat list, one level deep. flatMap maps each element to a collection and then flattens in a single step — so flatMap(f) equals map(f).flatten().

open as a page

What does zipWithNext do, and how would you use it to detect changes or compute deltas in a sequence?

level: middleimportance: should knowfreq 45%

basics

~20 s

zipWithNext pairs each element with the one right after it: (a,b), (b,c), (c,d). For n elements you get n-1 pairs. It is handy for comparing neighbors, like spotting where values change or computing gaps between them.

open as a page

You aggregate a very large data source in Kotlin: discuss eager-vs-lazy aggregation cost, integer overflow in sum/fold, and the difference between minByOrNull and minOfOrNull.

level: seniorimportance: should knowfreq 40%

basics

~20 s

On big data, chaining maps before aggregating with a List creates extra lists; using asSequence avoids that. Summing many Ints can silently overflow, so sum into Long. minByOrNull returns the element with the smallest key; minOfOrNull returns the smallest key value itself.

open as a page

How do `contains`/`in`, `indexOf`, and `indexOfFirst { }` work in Kotlin collections? What are the performance and equality considerations across List, Set, and Map?

level: seniorimportance: should knowfreq 55%

basics

~20 s

x in list (or list.contains(x)) checks if an element is present. indexOf(x) returns its position or -1 if absent. indexOfFirst { } finds the position of the first element matching a condition, or -1. Sets and maps check membership much faster than lists.

open as a page

Explain `take`, `drop`, `takeLast`, `dropLast`, `takeWhile`, `dropWhile`, and `slice` in Kotlin. How do they handle out-of-range counts and what do they return?

level: seniorimportance: should knowfreq 60%

basics

~20 s

take(n) keeps the first n elements; drop(n) skips them. takeLast/dropLast work from the end. The While versions cut at the first element that fails a condition. slice picks elements by index range or list. They return new collections and don't mutate.

open as a page

When would you use `groupingBy().eachCount()` instead of `groupBy`, and what advantages does the `Grouping` abstraction give you?

level: seniorimportance: should knowfreq 55%

basics

~10 s

Use groupingBy().eachCount() when you only need counts per key. It tallies directly into a map of counts instead of building lists first, so it's more efficient. Grouping also supports custom fold/reduce per group.

open as a page

Distinguish reversed(), asReversed(), and sortedDescending(). What does reversing a comparator with reversed() do, and how does stability interact with these?

level: seniorimportance: should knowfreq 45%

basics

~20 s

reversed() flips the current order into a new list. asReversed() gives a live reversed view without copying. sortedDescending() actually sorts from high to low. Reversing a list is not the same as sorting it descending.

open as a page

What does filterIsInstance do, and how does it differ from filter { it is T } plus a manual cast? Why does it need a reified type?

level: seniorimportance: should knowfreq 58%

basics

~20 s

filterIsInstance keeps only the elements that are of a given type and gives you back a list already typed as that type, so you do not have to cast each one yourself. It needs the type known at compile time to do this safely.

open as a page

When processing a very large or streaming input, how do windowed/chunked/zip behave on a List vs a Sequence, and what are the allocation and correctness implications?

level: seniorimportance: should knowfreq 30%

basics

~20 s

On a List these operators run eagerly and build all the result lists at once. On a Sequence they are lazy and produce windows/chunks on demand, so you can process huge or streaming data without holding everything in memory.

open as a page

What are the *To variants (mapTo, filterTo, flatMapTo, mapNotNullTo, etc.) and when would you choose them over the plain operators?

level: seniorimportance: nice to knowfreq 40%

basics

~20 s

The *To versions do the same transform but write the results into a collection you supply, instead of creating a brand-new list. You use them when you want to control the destination type or gather results from several sources into one collection.

open as a page

showing 1–30 of 32