Grouping, association, and map lookup
Choose based on cardinality: can one key have one value, or many values?
| Operation | Result shape | Duplicate-key behavior |
|---|---|---|
associateBy | Map<K, T> | Later item replaces earlier item |
groupBy | Map<K, List<T>> | Every item is retained in a list |
groupingBy | Grouping<T, K> | Deferred grouping source for aggregation |
One value versus many values
data class Employee(val id: Int, val name: String, val department: String)
fun main() {
val employees = listOf(
Employee(1, "Rakesh", "Android"),
Employee(2, "Anu", "Backend"),
Employee(3, "Sam", "Android"),
)
val byId: Map<Int, Employee> = employees.associateBy { it.id }
val byDepartment: Map<String, List<Employee>> =
employees.groupBy { it.department }
println(byId[2]?.name) // Anu
println(byDepartment["Android"].orEmpty()) // Rakesh and Sam
}
Map lookup returns a nullable value because the key may be absent. orEmpty() is useful only when “missing group means empty group” is the intended domain rule.
Counting without constructing lists per key
data class Employee(val name: String, val department: String)
fun main() {
val employees = listOf(
Employee("A", "Android"),
Employee("B", "Backend"),
Employee("C", "Android"),
)
val counts = employees
.groupingBy { it.department }
.eachCount()
println(counts) // {Android=2, Backend=1}
}
groupBy constructs Map<K, List<T>>. groupingBy creates a grouping abstraction consumed by operations such as eachCount, fold, or aggregate; it is useful when the final result is an aggregate rather than lists.
Duplicate IDs are a policy decision
data class User(val id: Int, val name: String)
fun main() {
val users = listOf(User(1, "Old"), User(1, "New"))
val byId = users.associateBy { it.id }
println(byId) // {1=User(id=1, name=New)}
}
If duplicates violate the server or database contract, overwriting silently is dangerous. Detect them before choosing a winner:
val duplicates = users.groupBy { it.id }.filterValues { it.size > 1 }
require(duplicates.isEmpty()) { "Duplicate user IDs: ${duplicates.keys}" }
Interview questions
- Why did an earlier value disappear after
associateBy? - What is the inferred type returned by
groupBy? - When is
groupingBy().eachCount()preferable togroupBy()? - Why does
map[key]returnV??