In Kotlin, associateBy, partition, and zip are collection operations that help transform or split collections.
associateBy
associateBy creates a Map from a collection by choosing a key for each element.
data class User(val id: Int, val name: String)
val users = listOf(
User(1, "Alice"),
User(2, "Bob"),
User(3, "Charlie")
)
val usersById = users.associateBy { user -> user.id }
println(usersById)
Output:
{
1=User(id=1, name=Alice),
2=User(id=2, name=Bob),
3=User(id=3, name=Charlie)
}
You can also choose both the key and the value:
val namesById = users.associateBy(
keySelector = { it.id },
valueTransform = { it.name }
)
println(namesById)
Output:
{1=Alice, 2=Bob, 3=Charlie}
If multiple elements produce the same key, the last one wins:
val words = listOf("one", "two", "three", "ten")
val byFirstLetter = words.associateBy { it.first() }
println(byFirstLetter)
Output:
{o=one, t=ten}
Here, "ten" replaces "two" and "three" for key 't'.
partition
partition splits a collection into two lists based on a predicate.
It returns a Pair<List<T>, List<T>>:
firstcontains elements where the predicate istruesecondcontains elements where the predicate isfalse
val numbers = listOf(1, 2, 3, 4, 5, 6)
val result = numbers.partition { it % 2 == 0 }
val evens = result.first
val odds = result.second
println(evens)
println(odds)
Output:
[2, 4, 6]
[1, 3, 5]
Commonly, you destructure the result:
val (evens, odds) = numbers.partition { it % 2 == 0 }
println(evens)
println(odds)
Example with objects:
data class Task(val title: String, val done: Boolean)
val tasks = listOf(
Task("Write tests", true),
Task("Fix bug", false),
Task("Deploy", false)
)
val (completed, pending) = tasks.partition { it.done }
println(completed)
println(pending)
zip
zip combines two collections element by element.
val names = listOf("Alice", "Bob", "Charlie")
val ages = listOf(25, 30, 35)
val people = names.zip(ages)
println(people)
Output:
[(Alice, 25), (Bob, 30), (Charlie, 35)]
The result is a List<Pair<A, B>>.
You can destructure each pair:
for ((name, age) in names.zip(ages)) {
println("$name is $age years old")
}
Output:
Alice is 25 years old
Bob is 30 years old
Charlie is 35 years old
You can also provide a transform function:
val descriptions = names.zip(ages) { name, age ->
"$name is $age years old"
}
println(descriptions)
Output:
[Alice is 25 years old, Bob is 30 years old, Charlie is 35 years old]
If the collections have different sizes, zip stops at the shorter one:
val letters = listOf("A", "B", "C")
val numbers = listOf(1, 2)
println(letters.zip(numbers))
Output:
[(A, 1), (B, 2)]
Quick comparison
| Function | Purpose | Result |
|---|---|---|
associateBy |
Turns a collection into a Map |
Map<K, T> or Map<K, V> |
partition |
Splits a collection into two lists | Pair<List<T>, List<T>> |
zip |
Combines two collections element by element | List<Pair<A, B>> or List<R> |
Example using all three:
data class Person(val id: Int, val name: String, val age: Int)
val people = listOf(
Person(1, "Alice", 17),
Person(2, "Bob", 21),
Person(3, "Charlie", 30)
)
val peopleById = people.associateBy { it.id }
val (adults, minors) = people.partition { it.age >= 18 }
val namesWithAges = people.map { it.name }.zip(people.map { it.age })
println(peopleById)
println(adults)
println(minors)
println(namesWithAges)
Use:
associateBywhen you want lookup by a keypartitionwhen you want to split a list into matching and non-matching groupszipwhen you want to pair two collections by position
