How do I combine multiple collection operations in a single Kotlin chain?

In Kotlin, you can combine multiple collection operations by chaining functions like filter, map, sortedBy, take, groupBy, and others.

Each operation returns a new collection, so you can call the next operation directly on the result.

val numbers = listOf(1, 2, 3, 4, 5, 6)

val result = numbers
    .filter { it % 2 == 0 }
    .map { it * 10 }
    .sorted()

println(result) // [20, 40, 60]

Here’s what happens:

  1. filter { it % 2 == 0 } keeps only even numbers
  2. map { it * 10 } transforms each number
  3. sorted() sorts the result

You can also chain operations on objects:

data class User(
    val name: String,
    val age: Int,
    val active: Boolean
)

val users = listOf(
    User("Alice", 30, true),
    User("Bob", 17, true),
    User("Charlie", 25, false),
    User("Diana", 22, true)
)

val activeAdultNames = users
    .filter { it.active }
    .filter { it.age >= 18 }
    .map { it.name }
    .sorted()

println(activeAdultNames) // [Alice, Diana]

You can often combine related filters into one:

val activeAdultNames = users
    .filter { it.active && it.age >= 18 }
    .map { it.name }
    .sorted()

For maps, you can chain over entries:

val scores = mapOf(
    "Alice" to 90,
    "Bob" to 75,
    "Charlie" to 85
)

val passedNames = scores
    .filter { (_, score) -> score >= 80 }
    .map { (name, _) -> name }
    .sorted()

println(passedNames) // [Alice, Charlie]

If the collection is large or the chain is expensive, use asSequence() to make intermediate operations lazy:

val result = numbers
    .asSequence()
    .filter { it % 2 == 0 }
    .map { it * 10 }
    .sorted()
    .toList()

Use regular collection chains for simple cases, and asSequence() when you want to avoid creating intermediate collections during multi-step processing.

How do I group and count elements using groupBy and count in Kotlin?

In Kotlin, you can group elements with groupBy, then count how many items are in each group.

Basic example

val words = listOf("apple", "banana", "apricot", "blueberry", "avocado")

val countsByFirstLetter = words
    .groupBy { it.first() }
    .mapValues { (_, words) -> words.count() }

println(countsByFirstLetter)

Output:

{a=3, b=2}

Here:

  • groupBy { it.first() } groups words by their first letter.
  • mapValues { it.value.count() } converts each grouped list into its size/count.

You can also write it as:

val countsByFirstLetter = words
    .groupBy { it.first() }
    .mapValues { it.value.size }

Counting objects by a property

data class Person(val name: String, val city: String)

val people = listOf(
    Person("Alice", "London"),
    Person("Bob", "Paris"),
    Person("Charlie", "London"),
    Person("Diana", "Paris"),
    Person("Eve", "Berlin")
)

val peopleByCity = people
    .groupBy { it.city }
    .mapValues { it.value.count() }

println(peopleByCity)

Output:

{London=2, Paris=2, Berlin=1}

More efficient option: groupingBy + eachCount

If you only need counts, prefer:

val countsByFirstLetter = words
    .groupingBy { it.first() }
    .eachCount()

This avoids creating intermediate lists for every group.

println(countsByFirstLetter)
// {a=3, b=2}

So the common choices are:

items.groupBy { key }.mapValues { it.value.count() }

or, more efficiently:

items.groupingBy { key }.eachCount()