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

How do I check if a collection is empty or contains an element in Kotlin?

In Kotlin, use isEmpty() / isNotEmpty() to check whether a collection has elements, and use in, contains(), or map-specific methods to check contents.

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

println(names.isEmpty())     // false
println(names.isNotEmpty())  // true

println("Alice" in names)    // true
println("Charlie" !in names) // true

For lists and sets:

val numbers = setOf(1, 2, 3)

if (numbers.isNotEmpty()) {
    println("The set has elements")
}

if (2 in numbers) {
    println("The set contains 2")
}

For maps, check keys or values explicitly:

val ages = mapOf(
    "Alice" to 25,
    "Bob" to 30
)

println(ages.isEmpty())              // false
println(ages.containsKey("Alice"))   // true
println(ages.containsValue(30))      // true
println("Bob" in ages)               // true, checks keys

You can also use contains():

val items = listOf("Book", "Pen")

println(items.contains("Book")) // true

In short:

  • collection.isEmpty() checks if it has no elements
  • collection.isNotEmpty() checks if it has at least one element
  • element in collection checks if an element exists
  • element !in collection checks if an element does not exist
  • map.containsKey(key) checks for a key
  • map.containsValue(value) checks for a value