Skip to main content

Understanding Kotlin Collections

1. Working with Lists

Method Description Example
listOf() Creates an immutable list val numbers = listOf(1, 2, 3, 4)
mutableListOf() Creates a mutable list val mutableNumbers = mutableListOf(1, 2, 3)
add() Adds an element to a mutable list mutableNumbers.add(4)
remove() Removes an element from a mutable list mutableNumbers.remove(2)
size Gets the number of elements in a list println(numbers.size)
get(index) Gets an element at a specific index val first = numbers.get(0)
indexOf() Finds the index of an element val index = numbers.indexOf(3)

Example: Filtering Lists

val numbers = listOf(1, 2, 3, 4, 5)
val evenNumbers = numbers.filter { it % 2 == 0 }
println(evenNumbers) // [2, 4]

Example: Mapping Lists

val numbers = listOf(1, 2, 3)
val doubled = numbers.map { it * 2 }
println(doubled) // [2, 4, 6]

2. Working with Sets

Method Description Example
emptySet() Creates an empty immutable set val empty = emptySet<String>()
setOf() Creates an immutable set with specified elements val colors = setOf("red", "green", "blue")
mutableSetOf() Creates a mutable set with specified elements val numbers = mutableSetOf(1, 2, 3)
toSet() Converts a collection to a set
val list = listOf(1, 2, 2, 3)
val set = list.toSet() // {1, 2, 3}
plus() Adds an element to a set
val set = setOf(1, 2)
val newSet = set + 3 // {1, 2, 3}
minus() Removes an element from a set
val set = setOf(1, 2, 3)
val newSet = set - 2 // {1, 3}
Note: Sets in Kotlin are unordered and do not allow duplicate elements.

Example: Set Operations

val setA = setOf(1, 2, 3)
val setB = setOf(3, 4, 5)

// Union
val union = setA + setB // {1, 2, 3, 4, 5}

// Intersection
val intersection = setA intersect setB // {3}

// Difference
val difference = setA subtract setB // {1, 2}

3. Working with Maps

Method Description Example
mapOf() Creates an immutable map val map = mapOf("key1" to "value1", "key2" to "value2")
mutableMapOf() Creates a mutable map val mutableMap = mutableMapOf("key1" to "value1")
get() Retrieves the value for a key val value = map["key1"]
put() Adds or updates a key-value pair mutableMap["key2"] = "value2"
remove() Removes a key-value pair mutableMap.remove("key1")
keys Returns a set of all keys val keys = map.keys
values Returns a collection of all values val values = map.values
entries Returns a set of key-value pairs for ((key, value) in map.entries) { println("$key = $value") }
Note: Maps in Kotlin are immutable by default unless created with mutableMapOf().
Warning: Accessing a non-existent key returns null in Kotlin maps.

Map Operations Summary

  • Creation: Use mapOf() for immutable, mutableMapOf() for mutable.
  • Access: Use [key] for reading, [key] = value for writing.
  • Iteration: Use entries to iterate over key-value pairs.

4. Using Collection Functions

Example: Filtering and Mapping

val numbers = listOf(1, 2, 3, 4, 5, 6)
val evenSquares = numbers
    .filter { it % 2 == 0 }
    .map { it * it }
println(evenSquares) // [4, 16, 36]
Function Description Example
filter Returns a list containing only elements that satisfy the predicate list.filter { it > 5 }
map Transforms each element using the provided function list.map { it * 2 }
flatMap Maps each element to a collection and flattens the result list.flatMap { it.split(" ") }
find Returns the first element matching the predicate, or null list.find { it == 3 }
firstOrNull Returns the first element or null if list is empty list.firstOrNull()
any Checks if any element satisfies the predicate list.any { it > 10 }
all Checks if all elements satisfy the predicate list.all { it > 0 }
count Returns the number of elements matching the predicate list.count { it % 2 == 0 }
groupBy Groups elements by a key function list.groupBy { it % 2 }
associateBy Creates a map using a key function list.associateBy { it.name }
Note: These functions are lazy in Kotlin, meaning they don't process elements until the result is consumed.

Example: Reducing Collections

val numbers = listOf(1, 2, 3, 4)
val sum = numbers.reduce { acc, value -> acc + value }
println(sum) // 10

val product = numbers.fold(1) { acc, value -> acc * value }
println(product) // 24
Function Description Example
reduce Reduces the collection to a single value using a binary operation list.reduce { a, b -> a + b }
fold Reduces the collection to a single value with an initial accumulator list.fold(0) { acc, value -> acc + value }
sumOf Computes the sum of a numeric property for each element list.sumOf { it.value }
maxOf Returns the maximum value of a numeric property list.maxOf { it.value }
minOf Returns the minimum value of a numeric property list.minOf { it.value }

Example: Sorting and Ordering

val numbers = listOf(3, 1, 4, 1, 5)
val sorted = numbers.sorted()
println(sorted) // [1, 1, 3, 4, 5]

val descending = numbers.sortedDescending()
println(descending) // [5, 4, 3, 1, 1]

val byLength = listOf("cat", "elephant", "dog")
    .sortedBy { it.length }
println(byLength) // [cat, dog, elephant]
Function Description Example
sorted Returns a new list sorted in natural order list.sorted()
sortedDescending Returns a new list sorted in descending order list.sortedDescending()
sortedBy Sorts by a property function list.sortedBy { it.name }
sortedByDescending Sorts by a property function in descending order list.sortedByDescending { it.name }
sortBy Sorts the list in place (mutable) list.sortBy { it.name }
sortDescendingBy Sorts the list in place in descending order list.sortByDescending { it.name }

5. Iterating Collections

Example: Using forEach to iterate over a list

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

numbers.forEach { number ->
    println(number)
}
Method Description Usage
forEach Iterates over each element and executes a block of code list.forEach { item -> ... }
forEachIndexed Iterates with index access list.forEachIndexed { index, item -> ... }
iterator Provides an iterator for manual iteration control val iter = list.iterator()

Example: Using forEachIndexed to access index and value

val fruits = listOf("apple", "banana", "cherry")

fruits.forEachIndexed { index, fruit ->
    println("Fruit at index $index is $fruit")
}
Note: forEach is the most common and idiomatic way to iterate over collections in Kotlin.

6. Transforming Collections

Method Description Example
map Transforms each element to a new form
val numbers = listOf(1, 2, 3)
val doubled = numbers.map { it * 2 }
// Result: [2, 4, 6]
mapNotNull Transforms each element and filters out nulls
val strings = listOf("1", "2", null, "4")
val ints = strings.mapNotNull { it?.toInt() }
// Result: [1, 2, 4]
flatMap Flattens a collection of collections into one
val lists = listOf(listOf(1, 2), listOf(3, 4))
val flattened = lists.flatMap { it }
// Result: [1, 2, 3, 4]
groupBy Groups elements by a key function
val words = listOf("apple", "banana", "cherry")
val grouped = words.groupBy { it.first() }
// Result: {'a' => ["apple"], 'b' => ["banana"], 'c' => ["cherry"]}
associateBy Creates a map from elements using a key function
val fruits = listOf("apple", "banana", "cherry")
val fruitMap = fruits.associateBy { it.length }
// Result: {5 => "apple", 6 => "banana", 6 => "cherry"}

Example: Using map and flatMap together

val nestedLists = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6))
val flatMapped = nestedLists.flatMap { it.map { it * 2 } }
// Result: [2, 4, 6, 8, 10, 12]

7. Searching Collections

Method Description Return Type Example
find Returns the first element matching the predicate or null T?
val numbers = listOf(1, 2, 3, 4, 5)
val firstEven = numbers.find { it % 2 == 0 }
// Result: 2
findLast Returns the last element matching the predicate or null T?
val numbers = listOf(1, 2, 3, 4, 5)
val lastEven = numbers.findLast { it % 2 == 0 }
// Result: 4
firstOrNull Returns the first element or null if collection is empty T?
val numbers = listOf(1, 2, 3, 4, 5)
val first = numbers.firstOrNull()
// Result: 1
lastOrNull Returns the last element or null if collection is empty T?
val numbers = listOf(1, 2, 3, 4, 5)
val last = numbers.lastOrNull()
// Result: 5
any Checks if any element matches the predicate Boolean
val numbers = listOf(1, 2, 3, 4, 5)
val hasEven = numbers.any { it % 2 == 0 }
// Result: true
all Checks if all elements match the predicate Boolean
val numbers = listOf(1, 2, 3, 4, 5)
val allEven = numbers.all { it % 2 == 0 }
// Result: false
none Checks if no elements match the predicate Boolean
val numbers = listOf(1, 2, 3, 4, 5)
val noneEven = numbers.none { it % 2 == 0 }
// Result: false
count Counts elements matching the predicate or all if no predicate Int
val numbers = listOf(1, 2, 3, 4, 5)
val evenCount = numbers.count { it % 2 == 0 }
// Result: 2
Note: These methods return null for find, firstOrNull, and lastOrNull when no element is found.

Search Methods Summary

  • find: Returns first matching element or null
  • findLast: Returns last matching element or null
  • firstOrNull: Returns first element or null
  • lastOrNull: Returns last element or null
  • any: Checks if any element matches predicate
  • all: Checks if all elements match predicate
  • none: Checks if no elements match predicate
  • count: Counts elements matching predicate

8. Sorting Collections

Method Description Return Type Example
sorted() Returns a new list with elements sorted in natural order List<T>
val numbers = listOf(3, 1, 4, 1, 5)
val sorted = numbers.sorted()
// Result: [1, 1, 3, 4, 5]
sortedDescending() Returns a new list with elements sorted in descending order List<T>
val numbers = listOf(3, 1, 4, 1, 5)
val sorted = numbers.sortedDescending()
// Result: [5, 4, 3, 1, 1]
sortBy() Sorts the list in-place by a specified property Unit
data class Person(val name: String, val age: Int)
val people = mutableListOf(Person("Alice", 30), Person("Bob", 25))
people.sortBy { it.age }
// Result: [Bob, Alice]
sortWith() Sorts the list in-place using a custom comparator Unit
val numbers = mutableListOf(3, 1, 4, 1, 5)
numbers.sortWith(compareByDescending { it })
// Result: [5, 4, 3, 1, 1]
sortedBy() Returns a new list sorted by a specified property List<T>
data class Person(val name: String, val age: Int)
val people = listOf(Person("Alice", 30), Person("Bob", 25))
val sorted = people.sortedBy { it.age }
// Result: [Bob, Alice]
sortedByDescending() Returns a new list sorted by a specified property in descending order List<T>
data class Person(val name: String, val age: Int)
val people = listOf(Person("Alice", 30), Person("Bob", 25))
val sorted = people.sortedByDescending { it.age }
// Result: [Alice, Bob]

9. Using Sequences for Lazy Evaluation

Sequences in Kotlin provide a way to perform lazy evaluation on collections, which can improve performance by avoiding unnecessary intermediate operations.

Method Description Return Type Notes
asSequence() Converts a collection into a sequence. Sequence<T> Used to enable lazy evaluation.
map() Transforms each element of the sequence. Sequence<R> Lazily applied to elements.
filter() Filters elements based on a predicate. Sequence<T> Lazily applied to elements.
take() Take the first n elements of a sequence. Sequence<T> Lazily applied to elements.
toList() Converts the sequence back to a list. List<T> Force evaluation of the sequence.

Example: Lazy Evaluation with Sequences

val numbers = (1..1000000).asSequence()
    .filter { it % 2 == 0 }
    .map { it * 2 }
    .take(10)
    .toList()

println(numbers)
Note: Sequences are particularly useful when chaining multiple operations on large datasets where intermediate collections would be inefficient.

10. Converting Between Collection Types

Collection Type Conversion Method Description
List<T> toMutableList() Creates a mutable copy of the list
List<T> toSet() Converts list to a set, removing duplicates
List<T> toMap() Converts list to a map using element as key
Set<T> toList() Converts set to a list
Set<T> toMutableList() Creates a mutable copy of the set
Map<K, V> keys Returns a set of keys from the map
Map<K, V> values Returns a collection of values from the map

Example: Converting List to Set

val list = listOf(1, 2, 2, 3, 4)
val set = list.toSet()
println(set) // Output: [1, 2, 3, 4]

Example: Converting List to Map

val list = listOf("a" to 1, "b" to 2)
val map = list.toMap()
println(map) // Output: {a=1, b=2}

11. Partitioning Collections

Function Description Example Returns
partition(predicate) Partitions a collection into two lists based on a predicate.
val numbers = listOf(1, 2, 3, 4, 5, 6)
val (evens, odds) = numbers.partition { it % 2 == 0 }
// evens: [2, 4, 6], odds: [1, 3, 5]
List<T> and List<T>
groupBy(keySelector) Groups elements by a key function into a map.
val words = listOf("apple", "banana", "cherry")
val grouped = words.groupBy { it.first() }
// grouped: {a=[apple], b=[banana], c=[cherry]}
Map<K, List<T>>
chunked(size) Splits a collection into chunks of a specified size.
val numbers = listOf(1, 2, 3, 4, 5, 6)
val chunks = numbers.chunked(2)
// chunks: [[1, 2], [3, 4], [5, 6]]
List<List<T>>

12. Working with Collection Operations

Example: Filtering and Transforming Collections

val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val evenNumbers = numbers.filter { it % 2 == 0 }
val doubledEven = evenNumbers.map { it * 2 }

println(evenNumbers) // [2, 4, 6, 8, 10]
println(doubledEven) // [4, 8, 12, 16, 20]
Operation Description Example
filter Returns a list containing only elements that satisfy the predicate list.filter { it > 5 }
map Transforms each element using the provided function list.map { it * 2 }
flatMap Flattens a collection of collections into one list list.flatMap { it.split(" ") }
groupBy Groups elements by a key function into a map list.groupBy { it.length }
fold Accumulates a value by applying a function to each element list.fold(0) { acc, i -> acc + i }
reduce Accumulates a value by applying a function to each element (without initial) list.reduce { acc, i -> acc + i }
Note: fold and reduce differ in that fold takes an initial value, while reduce uses the first element as the initial accumulator.

Example: Using fold to Build a String

val items = listOf("apple", "banana", "cherry")
val result = items.fold("") { acc, item ->
    if (acc.isEmpty()) item else "$acc, $item"
}
println(result) // apple, banana, cherry

Was this article helpful?