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

How do I access elements safely in Kotlin collections?

In Kotlin, you can access collection elements safely by using functions that return null instead of throwing exceptions when an index/key is missing.

Lists / arrays: use getOrNull

val items = listOf("A", "B", "C")

val first = items.getOrNull(0)   // "A"
val missing = items.getOrNull(10) // null

This is safer than:

val missing = items[10] // Throws IndexOutOfBoundsException

You can combine it with the Elvis operator:

val value = items.getOrNull(10) ?: "Default value"

Lists / arrays: use getOrElse

If you want a fallback value:

val items = listOf("A", "B", "C")

val value = items.getOrElse(10) { index ->
    "No item at index $index"
}

First / last elements safely

Instead of first() or last(), which throw if the collection is empty, use:

val items = emptyList<String>()

val first = items.firstOrNull()
val last = items.lastOrNull()

With a predicate:

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

val firstEven = numbers.firstOrNull { it % 2 == 0 } // 2
val firstBig = numbers.firstOrNull { it > 10 }      // null

Single element safely

Use singleOrNull() when you expect exactly one matching element:

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

val onlyAlice = users.singleOrNull { it == "Alice" } // "Alice"
val onlyZoe = users.singleOrNull { it == "Zoe" }     // null

Note: singleOrNull() also returns null if there is more than one match.

Maps: safe access by key

Map access already returns nullable values:

val ages = mapOf("Alice" to 30)

val aliceAge = ages["Alice"] // 30
val bobAge = ages["Bob"]     // null

Use a default if needed:

val bobAge = ages["Bob"] ?: 0

Or use getOrDefault:

val bobAge = ages.getOrDefault("Bob", 0)

Check bounds manually if needed

val items = listOf("A", "B", "C")
val index = 2

if (index in items.indices) {
    println(items[index])
}

Summary

Prefer these safe APIs:

list.getOrNull(index)
list.getOrElse(index) { default }
list.firstOrNull()
list.lastOrNull()
list.singleOrNull()
map[key] ?: default
map.getOrDefault(key, default)

Use direct indexing like list[index] only when you are certain the index is valid.