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()

How do I transform nested collections using flatMap in Kotlin?

In Kotlin, flatMap is used to transform each element into a collection and then flatten the results into a single list.

Basic idea

val result = items.flatMap { item ->
    // return a collection for each item
}

It is similar to:

items.map { ... }.flatten()

but more concise.


Example: flatten nested lists

val nested = listOf(
    listOf(1, 2),
    listOf(3, 4),
    listOf(5)
)

val flattened = nested.flatMap { it }

println(flattened)

Output:

[1, 2, 3, 4, 5]

Transform while flattening

val words = listOf("hi", "cat", "dog")

val letters = words.flatMap { word ->
    word.toList()
}

println(letters)

Output:

[h, i, c, a, t, d, o, g]

Each word becomes a list of characters, and flatMap combines them into one list.


Example with objects

data class Department(
    val name: String,
    val employees: List<String>
)

val departments = listOf(
    Department("Engineering", listOf("Alice", "Bob")),
    Department("HR", listOf("Carol"))
)

val allEmployees = departments.flatMap { department ->
    department.employees
}

println(allEmployees)

Output:

[Alice, Bob, Carol]

Transform nested values

data class Order(
    val id: Int,
    val items: List<String>
)

val orders = listOf(
    Order(1, listOf("Book", "Pen")),
    Order(2, listOf("Laptop"))
)

val itemDescriptions = orders.flatMap { order ->
    order.items.map { item ->
        "Order ${order.id}: $item"
    }
}

println(itemDescriptions)

Output:

[Order 1: Book, Order 1: Pen, Order 2: Laptop]

Here:

  1. Each Order is transformed into a List<String>
  2. flatMap flattens all those lists into one List<String>

map vs flatMap

Using map:

val result = orders.map { order ->
    order.items
}

Result type:

List<List<String>>

Using flatMap:

val result = orders.flatMap { order ->
    order.items
}

Result type:

List<String>

Rule of thumb

Use:

map

when each input becomes one output.

Use:

flatMap

when each input becomes many outputs, and you want a single flattened result.

val users = listOf(
    User("Alice", listOf("admin", "editor")),
    User("Bob", listOf("viewer"))
)

val roles = users.flatMap { it.roles }

Result:

[admin, editor, viewer]

How do I use map, filter and foreach with Kotlin collections?

In Kotlin collections:

  • map transforms each element into a new value.
  • filter keeps only elements that match a condition.
  • forEach performs an action for each element.

map: transform elements

Use map when you want to create a new collection by changing each item.

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

val doubled = numbers.map { number ->
    number * 2
}

println(doubled) // [2, 4, 6, 8]

You can use it when the lambda has one parameter:

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

val doubled = numbers.map { it * 2 }

println(doubled) // [2, 4, 6, 8]

filter: keep matching elements

Use filter when you want only items that satisfy a condition.

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

val evenNumbers = numbers.filter { it % 2 == 0 }

println(evenNumbers) // [2, 4, 6]

Another example with strings:

val names = listOf("Alice", "Bob", "Charlie", "Anna")

val namesStartingWithA = names.filter { it.startsWith("A") }

println(namesStartingWithA) // [Alice, Anna]

forEach: perform an action

Use forEach when you want to do something with each element, such as printing.

val names = listOf("Alice", "Bob", "Charlie")

names.forEach { name ->
    println(name)
}

Using it:

val names = listOf("Alice", "Bob", "Charlie")

names.forEach {
    println(it)
}

Chaining them together

You can combine filter, map, and forEach.

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

numbers
    .filter { it % 2 == 0 }
    .map { it * 10 }
    .forEach { println(it) }

Output:

20
40
60

This means:

  1. Keep only even numbers: [2, 4, 6]
  2. Multiply each by 10: [20, 40, 60]
  3. Print each result

Example with objects

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

val users = listOf(
    User("Alice", 25),
    User("Bob", 17),
    User("Charlie", 30)
)

val adultNames = users
    .filter { it.age >= 18 }
    .map { it.name }

println(adultNames) // [Alice, Charlie]

Important difference

map and filter return new collections:

val numbers = listOf(1, 2, 3)

val doubled = numbers.map { it * 2 }

println(numbers) // [1, 2, 3]
println(doubled) // [2, 4, 6]

forEach is usually used for side effects and does not create a transformed list:

val numbers = listOf(1, 2, 3)

numbers.forEach { println(it) }

Quick summary

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

val squared = numbers.map { it * it }
// [1, 4, 9, 16, 25]

val greaterThanTwo = numbers.filter { it > 2 }
// [3, 4, 5]

numbers.forEach { println(it) }
// Prints each number

Use:

  • map when you want to transform values
  • filter when you want to select values
  • forEach when you want to perform an action for each value

How do I convert arrays to lists and vice versa in Kotlin?

In Kotlin, you can convert arrays to lists and lists to arrays using standard library functions.

Array to List

Use toList():

val array = arrayOf("a", "b", "c")

val list: List<String> = array.toList()

println(list) // [a, b, c]

If you want a mutable list, use toMutableList():

val array = arrayOf("a", "b", "c")

val mutableList: MutableList<String> = array.toMutableList()

mutableList.add("d")

println(mutableList) // [a, b, c, d]

List to Array

Use toTypedArray():

val list = listOf("a", "b", "c")

val array: Array<String> = list.toTypedArray()

println(array.contentToString()) // [a, b, c]

Primitive Arrays

Kotlin has special primitive array types like IntArray, DoubleArray, and BooleanArray.

IntArray to List

val intArray = intArrayOf(1, 2, 3)

val list: List<Int> = intArray.toList()

println(list) // [1, 2, 3]

List<Int> to IntArray

Use toIntArray():

val list = listOf(1, 2, 3)

val intArray: IntArray = list.toIntArray()

println(intArray.contentToString()) // [1, 2, 3]

Other primitive conversions work similarly:

val doubles: List<Double> = listOf(1.1, 2.2, 3.3)
val doubleArray: DoubleArray = doubles.toDoubleArray()

val booleans: List<Boolean> = listOf(true, false)
val booleanArray: BooleanArray = booleans.toBooleanArray()

Important Note: asList()

For object arrays, you can also use asList():

val array = arrayOf("a", "b", "c")

val list = array.asList()

The difference is:

val array = arrayOf("a", "b", "c")

val copiedList = array.toList()
val backedList = array.asList()
  • toList() creates a new list copy.
  • asList() returns a list backed by the original array.

Example:

val array = arrayOf("a", "b", "c")
val list = array.asList()

array[0] = "z"

println(list) // [z, b, c]

So in most cases, use:

array.toList()
list.toTypedArray()

And for primitive types:

intArray.toList()
list.toIntArray()

How do I sort a list of values in Kotlin?

In Kotlin, you usually sort a list with sorted():

val numbers = listOf(5, 2, 8, 1)

val sortedNumbers = numbers.sorted()

println(sortedNumbers) // [1, 2, 5, 8]

sorted() returns a new sorted list and does not change the original list.

For descending order, use sortedDescending():

val numbers = listOf(5, 2, 8, 1)

val sortedDescending = numbers.sortedDescending()

println(sortedDescending) // [8, 5, 2, 1]

For objects, sort by a property with sortedBy():

data class Person(val name: String, val age: Int)

val people = listOf(
    Person("Alice", 30),
    Person("Bob", 25),
    Person("Charlie", 35)
)

val sortedByAge = people.sortedBy { it.age }

println(sortedByAge)
// [Person(name=Bob, age=25), Person(name=Alice, age=30), Person(name=Charlie, age=35)]

If you have a mutable list and want to sort it in place, use sort():

val numbers = mutableListOf(5, 2, 8, 1)

numbers.sort()

println(numbers) // [1, 2, 5, 8]

Quick summary:

  • sorted() — returns a new ascending list
  • sortedDescending() — returns a new descending list
  • sortedBy { ... } — sorts by a property
  • sort() — sorts a mutable list in place