Kotlin provides a rich standard library for working with collections. Most collection operations are extension functions defined on Iterable or Sequence.
List
Ordered collection with duplicates allowed.
// Creating
val list = listOf(1, 2, 3) // read-only List<Int>
val mutableList = mutableListOf(1, 2, 3) // MutableList<Int>
val empty = emptyList<Int>() // empty list
val listByBuilder = buildList { // builder syntax (1.4+)
add(1)
add(2)
add(3)
}
// Access
list[0] // 1 — indexed access
list.getOrNull(10) // null — safe access
list.first() // 1
list.last() // 3
list.firstOrNull() // null if empty
// Add / remove (mutable only)
mutableList.add(4) // [1, 2, 3, 4]
mutableList.add(0, 0) // [0, 1, 2, 3, 4]
mutableList.removeAt(0) // removes element at index 0
mutableList.remove(3) // removes first occurrence of 3
// Transform
list.map { it * 2 } // [2, 4, 6]
list.filter { it > 1 } // [2, 3]
list.filterNotNull() // removes nulls from List<Int?>
list.mapNotNull { if (it > 1) it else null } // [2, 3]
// Flatten / zip
val nested = listOf(listOf(1, 2), listOf(3, 4))
nested.flatten() // [1, 2, 3, 4]
nested.flatMap { it.map { it * 2 } } // [2, 4, 6, 8]
val a = listOf("a", "b", "c")
val b = listOf(1, 2, 3)
a.zip(b) // [(a, 1), (b, 2), (c, 3)]
a.zip(b) { x, y -> "$x$y" } // [a1, b2, c3]
// Sort
val unsorted = listOf(3, 1, 2)
unsorted.sorted() // [1, 2, 3]
unsorted.sortedDescending() // [3, 2, 1]
unsorted.sortedBy { -it } // [3, 2, 1]
unsorted.sortedWith(compareByDescending { it }) // [3, 2, 1]
// Find
list.find { it > 1 } // 2 — first match or null
list.findLast { it > 1 } // 3
list.any { it > 2 } // true
list.all { it > 0 } // true
list.none { it > 10 } // true
list.count { it > 1 } // 2
// Group by
val items = listOf("apple", "avocado", "banana", "blueberry")
items.groupBy { it.first() } // {a=[apple, avocado], b=[banana, blueberry]}
// Partition
val (matched, rest) = list.partition { it > 1 } // matched=[2,3], rest=[1]
// Reduce / fold
list.reduce { acc, i -> acc + i } // 6
list.fold(0) { acc, i -> acc + i } // 6
list.runningReduce { acc, i -> acc + i } // [1, 3, 6]
// Join to string
list.joinToString(", ") // "1, 2, 3"
list.joinToString(prefix = "[", separator = ", ", postfix = "]") // "[1, 2, 3]"Set
Unordered collection with unique elements.
// Creating
val set = setOf(1, 2, 3, 2) // [1, 2, 3] — duplicates removed
val mutableSet = mutableSetOf(1, 2, 3) // MutableSet<Int>
val linkedSet = linkedSetOf(1, 2, 3) // preserves insertion order
val hashSet = hashSetOf(1, 2, 3) // HashSet<Int>
// Add / remove (mutable only)
mutableSet.add(4) // true if added
mutableSet.remove(1) // true if removed
// Check membership
set.contains(2) // true
2 in set // true — operator form
// Set operations
val a = setOf(1, 2, 3)
val b = setOf(2, 3, 4)
a union b // [1, 2, 3, 4]
a intersect b // [2, 3]
a subtract b // [1]Map
Key-value pairs. Keys are unique.
// Creating
val map = mapOf("a" to 1, "b" to 2, "c" to 3) // read-only Map<String, Int>
val mutableMap = mutableMapOf("a" to 1, "b" to 2) // MutableMap<String, Int>
val empty = emptyMap<String, Int>()
// From pairs
val pairs = listOf("a" to 1, "b" to 2)
val mapFromPairs = pairs.toMap()
// Access
map["a"] // 1 — returns null if key missing
map.getValue("a") // 1 — throws if missing
map.getOrDefault("z", 0) // 0
map["z"] ?: 0 // 0 — elvis operator
// Add / update (mutable only)
mutableMap["c"] = 3 // add or update
mutableMap.put("d", 4) // add or update, returns old value
mutableMap.putAll(mapOf("e" to 5, "f" to 6))
// Remove (mutable only)
mutableMap.remove("a") // removes key "a", returns value or null
mutableMap.remove("b", 2) // removes only if key->value matches
// Iterate
for ((key, value) in map) {
println("$key = $value")
}
map.forEach { (key, value) ->
println("$key = $value")
}
// Keys and values
map.keys // [a, b, c]
map.values // [1, 2, 3]
map.entries // [a=1, b=2, c=3]
// Transform
map.mapKeys { (k, _) -> k.uppercase() } // {A=1, B=2, C=3}
map.mapValues { (_, v) -> v * 2 } // {a=2, b=4, c=6}
// Filter
map.filterKeys { it.length == 1 } // keep keys matching predicate
map.filterValues { it > 1 } // keep values matching predicate
map.filter { (_, v) -> v > 1 } // keep entries matching predicate
// Get or put (mutable only)
mutableMap.getOrPut("g") { 7 } // returns value or computes and insertsSequences
Sequences are lazily evaluated — like Java Streams. Use for large or infinite collections.
// Creating
val seq = sequenceOf(1, 2, 3)
val seqFromList = listOf(1, 2, 3).asSequence()
val seqGenerate = generateSequence(0) { it + 1 } // infinite: 0, 1, 2, ...
val seqYield = sequence {
yield(1)
yieldAll(listOf(2, 3, 4))
}
// Operations (lazy — not evaluated until terminal)
val result = (1..100).asSequence()
.filter { it % 2 == 0 }
.map { it * 3 }
.take(5)
.toList() // [6, 12, 18, 24, 30]
// Terminal operations trigger evaluation
seq.toList() // List
seq.toSet() // Set
seq.first() // first element
seq.last() // last element
seq.count() // count
seq.fold(0) { acc, i -> acc + i } // reduce to single value
seq.forEach { println(it) } // iterate