Collection superpowers: filter, map, sumOf
Kotlin can do in one line what a loop takes six lines to say — keep the items you want, change every item, and total them up. After this you will describe what you want instead of spelling out how to get it.
Six lines that should be one
Here is a job you already know how to do. Out of a list of prices, keep only the expensive ones.
1val prices = listOf(3, 12, 7, 20, 5)
2val big = mutableListOf<Int>()
3for (p in prices) {
4 if (p >= 7) {
5 big.add(p)
6 }
7}
8println(big)That works. It prints [12, 7, 20]. But look at how much of it is machinery: making an empty box, walking the list, adding to the box. Only one fragment — p >= 7 — says anything about the actual task.
Kotlin has a shorter way:
val big = prices.filter { it >= 7 }Same answer. One line. And the only thing left on that line is the interesting bit.
Picture a production line in a jam factory.
The fruit rolls past a sieve — anything too small drops through and only the good ones carry on. Further along, a machine stamps a label on every jar that passes. At the end, a scale weighs the lot and prints one total.
Nobody stands at the belt saying "pick up jar, look at jar, put jar in crate, pick up next jar". You install the sieve, the stamper and the scale, and describe what each one does to one item. The belt handles the repetition.
filter is the sieve. map is the stamper. sumOf is the scale.
The brace is a tiny function
prices.filter { it >= 7 }Those braces hold a — a scrap of code with no name, handed to filter as an instruction. filter runs it once for every item.
Inside, is the item currently being looked at. Kotlin supplies that name automatically whenever the lambda takes exactly one input, so you do not have to invent one. Lesson 1.17 pulls lambdas apart properly; for now, read { it >= 7 } as "is this one seven or more?".
A lambda that answers true or false is called a . Every function on this page that asks a yes/no question takes one.
The three you will use every day
filter — keep the ones that pass
1val names = listOf("Ada", "Al", "Grace")
2println(names.filter { it.length > 2 })Prints [Ada, Grace]. hands back a new list containing only the items whose was true. filterNot keeps the opposite ones.
map — change every item
println(prices.map { it * 2 })Prints [6, 24, 14, 40, 10]. runs your lambda on each item and collects the results. The new list is always the same length as the old one — every item goes in, every item comes out changed.
It does not have to come out as the same , either:
println(names.map { it.length })Strings go in, numbers come out: [3, 2, 5].
The from Lesson 1.11 is a collection of key-and-value pairs. The map on this page is a function that transforms every item.
They are unrelated, and Kotlin genuinely uses one word for both. Tell them apart by where the word sits: mapOf(...) builds a collection, list.map { ... } transforms one.
sumOf — total up one number per item
println(names.sumOf { it.length })Prints 10, because 3 + 2 + 5 is ten. asks your lambda for a number from each item and adds them all together. When the items are already numbers, plain sum() does the same job with no lambda at all.
Eight more worth knowing now
| Written as | Hands back |
|---|---|
list.count { it > 5 } | How many items pass |
list.any { it > 5 } | true if at least one passes |
list.all { it > 5 } | true only if every one passes |
list.none { it > 5 } | true if not a single one passes |
list.maxOrNull() | The biggest item, or null if the list is empty |
list.sortedBy { it.length } | A new list in order of whatever you name |
list.firstOrNull { it > 5 } | The first passing item, or null |
list.joinToString(" & ") | One string with the items glued together |
Notice how many of those end in OrNull. An empty list has no biggest item, so those functions honestly say null rather than guessing. Lesson 1.13 is about handling that answer.
Chaining: the belt keeps going
Because each of these hands back a new , you can bolt the next one straight on to the end. That is :
1val total = prices
2 .filter { it >= 7 }
3 .map { it * 2 }
4 .sum()
5println(total)Read it top to bottom, like a sentence: take the prices, keep the ones from seven up, double each of them, add them together. It prints 78, because 12 + 7 + 20 is 39, and doubled that is 78.
None of these functions ever change the list you started with. prices still holds all five prices after every line above. Values you cannot accidentally alter are called , and they are one of the reasons Kotlin code tends to stay correct as it grows.
- Open Pocket Studio, tap Projects, and open your Kotlin practice project.
- Tap Editor and open
Playground.kt. - Select everything in the file and delete it.
- Type the eleven-line program from the walkthrough above.
- Tap Run and read the Output panel.
You should see exactly this:
1[12, 7, 20]
2[6, 24, 14, 40, 10]
339
4[Ada, Grace]
510
6Ada & Al & Grace- Now add one more line just before the closing brace:
println(prices). - Run again. All five original prices are still there, in their original order — proof that
filterandmapbuild new lists rather than editing the old one.
filter needs a yes/no answer from your lambda, and yours handed back a number. Usually you wrote { it * 2 } where you meant a comparison.{ it > 2 }. If you actually wanted to change each item rather than choose between them, use map instead of filter.it only exists when you have not named the lambda's input. As soon as you write { n -> ... }, the name is n and it stops existing.{ it > 7 } or { n -> n > 7 }. Do not mix them in the same braces.sumBy was an older name that has since been removed from Kotlin. Tutorials written before 2021 still use it.sumOf instead — same idea, and it copes with decimals as well as whole numbers.listOf() with nothing inside, so Kotlin has no way to know what kind of list you meant, and it refuses to guess.listOf<Int>(), or mutableListOf<String>(). Once there is at least one item in the brackets, Kotlin works it out by itself.maxOrNull hands back Int? — a number or null, because an empty list has no biggest item. You tried to add one to that without dealing with the null case.(prices.maxOrNull() ?: 0) + 1. Lesson 1.13 explains exactly what Kotlin is protecting you from here.- keeps the items that pass a ; the result is a new, possibly shorter list.
- runs a lambda on every item and collects the results; same length, possibly a different .
- turns each item into a number and totals them.
- is the automatic name for the current item when the lambda takes one input.
- None of these change the original — they always build a new one, which is what makes safe.
- Next: the most important safety idea in Kotlin. Why
nullexists, what a NullPointerException really is, and the two characters that make it a non-issue.