Skip to main content

List-specific operations

A List adds positional meaning to a collection: every element has an index. That enables indexed access, ranges, insertion, replacement, binary search, and in-place reordering.

Indexes, ranges, slice, and subList​

fun main() {
val values = listOf("A", "B", "C", "D", "E")

println(values.indices) // 0..4
println(values.lastIndex) // 4
println(values.slice(1..3)) // [B, C, D]
println(values.slice(listOf(4, 0))) // [E, A]
println(values.subList(1, 4)) // [B, C, D]
}
Open in Kotlin Playground

subList(from, to) uses an inclusive start and exclusive end. It is commonly a view backed by the original list, not an independent snapshot. Structural changes outside that view can invalidate it; copy with toList() when independent ownership is required.

Indexed mutation​

fun main() {
val values = mutableListOf("A", "D")
values.add(1, "B")
values.addAll(2, listOf("C1", "C2"))
values[2] = "C"
val removed = values.removeAt(3)

println(removed) // C2
println(values) // [A, B, C, D]

values.fill("X")
println(values) // [X, X, X, X]
}
Open in Kotlin Playground

Invalid indexes throw. Inserting/removing near the beginning of an ArrayList shifts later elements and is normally O(n).

Binary search requires compatible sorted order​

fun main() {
val sorted = listOf(10, 20, 30, 40)
println(sorted.binarySearch(30)) // 2

val missing = sorted.binarySearch(25)
println(missing) // negative
println(-missing - 1) // insertion index: 2
}
Open in Kotlin Playground

Calling binarySearch on unsorted data gives an undefined/meaningless search result. If a comparator sorted the list, the same ordering contract must be used for searching.

Adjacent pairs with zipWithNext​

fun main() {
val readings = listOf(10, 13, 12, 20)
println(readings.zipWithNext())
// [(10, 13), (13, 12), (12, 20)]

val changes = readings.zipWithNext { before, after -> after - before }
println(changes) // [3, -1, 8]
}
Open in Kotlin Playground

Unlike chunked(2), adjacent pairs overlap. A list of fewer than two elements produces an empty result.

New order versus in-place order​

Returns a new listMutates a MutableListSpecial behavior
sorted, sortedBysort, sortByOrdering
reversedreverseReverse order
shuffledshuffleRandom order
——asReversed() creates a backed reversed view
fun main() {
val original = mutableListOf(1, 2, 3)
val view = original.asReversed()
view[0] = 30

println(view) // [30, 2, 1]
println(original) // [1, 2, 30]

val snapshot = original.reversed()
original.add(4)
println(snapshot) // [30, 2, 1]
}
Open in Kotlin Playground
Ownership trap

subList and asReversed can share backing storage. Do not expose them as supposedly independent state snapshots across ViewModel/UI or coroutine ownership boundaries.

Interview questions​

  1. Why must binary search receive consistently sorted data?
  2. How is a negative binary-search result converted to an insertion point?
  3. What is the difference between reversed() and asReversed()?
  4. Why can repeated insertion at index zero be expensive for ArrayList?