Sorting and aggregating collections
Sorting decides order. Aggregation reduces many values into a smaller result such as a count, minimum, maximum, total, or domain summary.
Sorting values and objects
data class User(val name: String, val age: Int)
fun main() {
val users = listOf(
User("Sam", 30),
User("Anu", 25),
User("Rakesh", 30),
)
println(users.sortedBy { it.name })
println(users.sortedByDescending { it.age })
println(users.sortedWith(compareBy<User> { it.age }.thenBy { it.name }))
}
thenBy breaks ties: age is compared first, then name when ages are equal. Define null placement, case sensitivity, and locale-aware collation when user-visible ordering requires them.
New result versus in-place mutation
fun main() {
val original = mutableListOf(3, 1, 2)
val sortedCopy = original.sorted()
println(original) // [3, 1, 2]
println(sortedCopy) // [1, 2, 3]
original.sort()
println(original) // [1, 2, 3]
}
sorted,sortedBy, andsortedWithreturn a new list.sort,sortBy, andsortWithmutate a mutable list.
For Compose state, producing a new list usually makes state transitions clearer. For a private large buffer in a performance-sensitive algorithm, in-place sorting may be appropriate.
Aggregate operations
data class Order(val quantity: Int, val price: Double)
fun main() {
val orders = listOf(Order(2, 100.0), Order(1, 50.0))
println(orders.count { it.quantity > 1 })
println(orders.sumOf { it.quantity })
println(orders.sumOf { it.quantity * it.price })
println(orders.minOfOrNull { it.price })
println(orders.maxByOrNull { it.quantity })
}
Avoid Double for exact currency in production; use an appropriate decimal/minor-unit money model. A syntactically correct sumOf can still implement the wrong financial model.
fold can build a domain summary
data class Summary(val accepted: Int, val rejected: Int)
fun main() {
val results = listOf(true, false, true)
val summary = results.fold(Summary(0, 0)) { acc, accepted ->
if (accepted) acc.copy(accepted = acc.accepted + 1)
else acc.copy(rejected = acc.rejected + 1)
}
println(summary)
}
Predict before revealing
val values = mutableListOf(3, 1, 2)
val result = values.sortedDescending()
println(values)
println(result)
Reveal
The original remains [3, 1, 2]; the returned list is [3, 2, 1]. The sorted... family does not mutate the receiver.
Interview questions
- What is the difference between
sortedByandsortBy? - How do you sort by age and then by name?
- Why should financial totals avoid binary floating-point?
- When is
foldbetter than multiple separate collection passes?