Collection Functions: map, filter, and fold
Prerequisites: Lambdas and higher-order functions
Kotlin's collection functions, each taking a lambda, replace most hand-written loops.
map — transform every element
fun main() {
val prices = listOf(10.0, 20.0, 30.0)
println(prices.map { it * 1.2 })
val names = listOf("ada", "linus")
println(names.map { it.uppercase() })
println(names.map(String::length))
}
[12.0, 24.0, 36.0]
[ADA, LINUS]
[3, 5]
filter — keep matching elements
fun main() {
val nums = (1..10).toList()
println(nums.filter { it % 2 == 0 })
println(nums.filterNot { it % 2 == 0 })
println(nums.partition { it > 7 })
}
[2, 4, 6, 8, 10]
[1, 3, 5, 7, 9]
([8, 9, 10], [1, 2, 3, 4, 5, 6, 7])
partition splits into a pair: matches and non-matches.
fold and reduce — combine into one value
fun main() {
val nums = listOf(1, 2, 3, 4)
println(nums.fold(0) { sum, n -> sum + n })
println(nums.reduce { product, n -> product * n })
println(listOf("a", "b", "c").fold("") { acc, s -> acc + s.uppercase() })
}
10
24
ABC
fold starts from an initial value you give; reduce starts from the
first element (and throws on an empty list). For totals, sum() and
sumOf { } are simpler.
mapNotNull — transform and drop nulls
fun main() {
val inputs = listOf("1", "two", "3", "")
println(inputs.mapNotNull { it.toIntOrNull() })
}
[1, 3]
Grouping and counting
fun main() {
val words = listOf("apple", "avocado", "banana", "cherry", "blueberry")
println(words.groupBy { it.first() })
println(words.groupingBy { it.length }.eachCount())
println(words.associateWith { it.length })
println(words.sumOf { it.length })
}
{a=[apple, avocado], b=[banana, blueberry], c=[cherry]}
{5=1, 7=1, 6=2, 9=1}
{apple=5, avocado=7, banana=6, cherry=6, blueberry=9}
33
Chaining
fun main() {
val orders = listOf(120.0, 45.0, 300.0, 80.0)
val bigOrdersTotal = orders
.filter { it > 100 }
.map { it * 0.9 }
.sum()
println(bigOrdersTotal)
}
378.0
Common mistakes
- Using
forEachto build a new list.mapandfiltersay what you mean directly and return the result. - Chaining many steps over a very large collection — each step builds a whole new list. Sequences (Level 3) process elements lazily instead.
Practice
Given listOf("ada", "linus", "grace", "al"), produce a list of the names
longer than 2 letters, capitalized.
Show solution
fun main() {
val names = listOf("ada", "linus", "grace", "al")
println(names.filter { it.length > 2 }.map { it.replaceFirstChar(Char::uppercase) })
}
[Ada, Linus, Grace]