Collections

Kotlin lists, sets, maps, and sequences — creating, iterating, and transforming

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 inserts

Sequences

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