reduce and aggregate
Other ways to combine elements.
reduce and aggregate is a free Scala for Backend Engineering & Functional Programming lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Scala for Backend Engineering & Functional Programming learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
From Fold to Reduce
Sometimes you want to combine elements without supplying a separate seed value.
reduce uses the first element as the starting accumulator and combines the rest into it.
It is a leaner cousin of fold for cases where the element type and result type are the same.
reduce Basics
reduce takes a binary function (a, b) and folds it across the collection, with no explicit initial value.
For a sum, it simply adds every element together.
val xs = List(1, 2, 3, 4)
val total = xs.reduce((a, b) => a + b)
@main def run(): Unit =
println(total) // 10The Empty Collection Trap
Because reduce has no seed, calling it on an empty collection throws an UnsupportedOperationException.
fold and foldLeft are safe on empty collections because they fall back to the provided seed.
Reach for reduce only when you know the collection is non-empty.
// List.empty[Int].reduce(_ + _)
// throws UnsupportedOperationException
List.empty[Int].foldLeft(0)(_ + _) // safe, returns 0reduceOption for Safety
reduceOption returns an Option, giving None for an empty collection instead of throwing.
This is the safe way to reduce when emptiness is possible.
val xs = List(5, 9, 2)
val maybeMax = xs.reduceOption(_ max _)
@main def run(): Unit =
println(maybeMax) // Some(9)reduceLeft and reduceRight
Like fold, reduce has directional variants.
reduceLeft combines left to right, reduceRight right to left. Plain reduce makes no ordering guarantee for parallel collections, so use the explicit variant when direction matters.
val xs = List(1, 2, 3)
val l = xs.reduceLeft(_ - _) // (1-2)-3 = -4
val r = xs.reduceRight(_ - _) // 1-(2-3) = 2
@main def run(): Unit =
println((l, r)) // (-4, 2)Why aggregate Exists
fold and reduce require the accumulator and element types to relate simply.
aggregate is the most general fold: it lets the accumulator be a different type AND tells Scala how to merge partial accumulators, which matters for parallel processing.
aggregate Signature
aggregate takes a seed, a seqop that folds an element into the accumulator, and a combop that merges two accumulators.
On a sequential collection combop is rarely used; on a parallel one it joins the results of each chunk.
val xs = List(1, 2, 3, 4)
val sum = xs.aggregate(0)(
(acc, x) => acc + x, // seqop
(a, b) => a + b // combop
)
@main def run(): Unit = println(sum) // 10aggregate with a Different Type
Here aggregate folds a list of words into a single Int length total.
The seqop adds each word's length, while the combop adds two partial totals together.
The accumulator type (Int) differs from the element type (String).
val words = List("hi", "there", "you")
val chars = words.aggregate(0)(
(acc, w) => acc + w.length,
(a, b) => a + b
)
@main def run(): Unit = println(chars) // 10Parallel Aggregation
The real power of aggregate appears with parallel collections.
Each thread folds its own chunk with seqop, then the chunks are merged with combop. The two functions let Scala split and rejoin work safely.
// Conceptual: par splits the work
// val n = data.par.aggregate(0)(_ + _.length, _ + _)
// seqop runs per chunk, combop merges chunk resultsChoosing the Right Tool
Use reduce or reduceOption when the result type equals the element type and combining is associative.
Use foldLeft when you need a seed or a different result type sequentially.
Use aggregate when accumulator and element types differ and you want parallel-friendly merging.
// reduce: same type, non-empty, associative
// foldLeft: seed + different type, sequential
// aggregate: different type + parallel mergeCombining in One Pass
aggregate can compute several things at once by accumulating into a tuple.
Here we get both the sum and the count in a single pass, merging tuples in combop.
val xs = List(2, 4, 6, 8)
val (s, c) = xs.aggregate((0, 0))(
(acc, x) => (acc._1 + x, acc._2 + 1),
(a, b) => (a._1 + b._1, a._2 + b._2)
)
@main def run(): Unit = println((s, c)) // (20, 4)Quick Check
Decide which operation is safest for a possibly-empty list.
Recap
reduce combines elements with no seed, using the first element as the start; it throws on an empty collection, while reduceOption returns None instead.
aggregate is the most general fold: a seed, a seqop to fold elements, and a combop to merge partial accumulators for parallel work.
Pick reduce for same-type associative combining, foldLeft for sequential seeded folds, and aggregate when types differ or you go parallel.
Frequently asked questions
Is the “reduce and aggregate” lesson free?
Yes — the full text of “reduce and aggregate” is free to read here on the web, and the Scala for Backend Engineering & Functional Programming course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Scala for Backend Engineering & Functional Programming course, upgrade to CoddyKit PRO.
What will I learn in “reduce and aggregate”?
Other ways to combine elements. You practise Scala for Backend Engineering & Functional Programming with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Scala for Backend Engineering & Functional Programming?
No prior experience is required. Scala for Backend Engineering & Functional Programming on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “reduce and aggregate” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Scala for Backend Engineering & Functional Programming lesson?
Yes. Every Scala for Backend Engineering & Functional Programming lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Thinking Recursively
- Accumulator Patterns
- foldLeft and foldRight
- reduce and aggregate