Skip to content
AgileLogics
6 min read

Working with Collections

Prerequisites: Collection functions, Data classes

Real programs spend much of their time sorting, grouping, and searching lists of objects. Kotlin's collection functions make this concise.

data class Order(val customer: String, val total: Double, val paid: Boolean)

val orders = listOf(
    Order("Ada", 120.0, true),
    Order("Linus", 45.0, false),
    Order("Ada", 80.0, true),
    Order("Grace", 300.0, true),
)

fun main() {
    // Sorting by one or more properties
    println(orders.sortedByDescending { it.total }.map { it.customer })
    println(orders.sortedWith(compareBy({ it.customer }, { it.total })).map { it.total })

    // Searching
    println(orders.first { !it.paid }.customer)
    println(orders.firstOrNull { it.total > 1000 })
    println(orders.count { it.paid })

    // Grouping and totaling
    val spentByCustomer = orders.groupBy { it.customer }
        .mapValues { (_, list) -> list.sumOf { it.total } }
    println(spentByCustomer)

    // Lookup maps
    val byCustomer = orders.associateBy { it.customer }
    println(byCustomer["Grace"]?.total)

    // Largest and smallest by a property
    println(orders.maxBy { it.total }.customer)
}
[Grace, Ada, Ada, Linus]
[80.0, 120.0, 300.0, 45.0]
Linus
null
3
{Ada=200.0, Linus=45.0, Grace=300.0}
300.0
Grace
  • compareBy sorts by several properties in turn — here by customer, then by total.
  • groupBy returns a map of lists; mapValues transforms each list.
  • associateBy builds a lookup map. If two elements share a key, the last one wins.

Reshaping collections

fun main() {
    val names = listOf("Ada", "Linus", "Grace")
    val scores = listOf(92, 78, 88)

    println(names.zip(scores))
    println((1..7).chunked(3))
    println((1..5).windowed(2))
    println(listOf(listOf(1, 2), listOf(3)).flatten())
    println(names.flatMap { name -> name.take(2).toList() })
}
[(Ada, 92), (Linus, 78), (Grace, 88)]
[[1, 2, 3], [4, 5, 6], [7]]
[[1, 2], [2, 3], [3, 4], [4, 5]]
[1, 2, 3]
[A, d, L, i, G, r]

Practice

Using the orders list, print the names of customers with unpaid orders, and the average total of paid orders.

Show solution
data class Order(val customer: String, val total: Double, val paid: Boolean)

fun main() {
    val orders = listOf(
        Order("Ada", 120.0, true),
        Order("Linus", 45.0, false),
        Order("Ada", 80.0, true),
        Order("Grace", 300.0, true),
    )

    println(orders.filterNot { it.paid }.map { it.customer })
    println(orders.filter { it.paid }.map { it.total }.average())
}
[Linus]
166.66666666666666