Aggregating with reduce and fold

Built-in Aggregates

Example

data class Item(val name: String, val price: Int, val qty: Int)

fun main() {
    val cart = listOf(Item("Shirt", 799, 2), Item("Jeans", 1499, 1), Item("Cap", 299, 3))
    println("Sum of prices: ${cart.sumOf { it.price }}")
    println("Cart total:    ${cart.sumOf { it.price * it.qty }}")
    println("Average price: ${cart.map { it.price }.average()}")
    println("Costliest:     ${cart.maxBy { it.price }.name}")
    println("Cheapest:      ${cart.minByOrNull { it.price }?.name}")
}

Output

Sum of prices: 2597
Cart total:    3994
Average price: 865.6666666666666
Costliest:     Jeans
Cheapest:      Cap

reduce vs fold

reduce starts with the first element and combines the rest into it. fold starts with an initial value you give, so it works on empty lists and the result can be a different type.

Example

fun main() {
    val nums = listOf(2, 3, 4)
    println(nums.reduce { acc, n -> acc * n })               // 24
    println(nums.fold(10) { acc, n -> acc + n })             // 10 + 2 + 3 + 4
    println(nums.fold("") { acc, n -> acc + "[$n]" })        // different result type

    val transactions = listOf(+5000, -1200, -300, +800)
    val balances = transactions.runningFold(0) { bal, t -> bal + t }
    println(balances)

    println(emptyList<Int>().fold(0) { a, b -> a + b })      // 0
    // emptyList<Int>().reduce { a, b -> a + b }  -> throws: Empty collection can't be reduced
}

Output

24
19
[2][3][4]
[0, 5000, 3800, 3500, 4300]
0