Skip to content
AgileLogics
6 min read

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 forEach to build a new list. map and filter say 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]