Reading — step 1 of 7
Learn
fold and scan are the two most powerful sequence operations. Programming in Scala devotes a chapter to higher-order operations, and these are the heavyweights.
foldLeft — left-to-right reduction
val nums = List(1, 2, 3, 4, 5)
val sum = nums.foldLeft(0)((acc, n) => acc + n) // 15
val product = nums.foldLeft(1)((acc, n) => acc * n) // 120
val max = nums.foldLeft(Int.MinValue)((acc, n) => acc max n) // 5
foldLeft(initial)(combineFn):
- Start with
initial - For each element, combine
accand the element - Return the final accumulator
Use this when you need a single result from a sequence.
foldRight — right-to-left
val nums = List(1, 2, 3, 4, 5)
nums.foldRight(0)((n, acc) => n + acc) // also 15, but right-associated
nums.foldRight(List.empty[Int])((n, acc) => (n * 2) :: acc) // List(2, 4, 6, 8, 10)
Note the parameter order is reversed: foldRight(initial)((element, acc) => ...). Useful for building up structures with prepend (cheap on List).
foldLeft is tail-recursive — preferred for large lists. foldRight isn't (without trampolining) — can stack-overflow on huge lists.
reduceLeft / reduceRight
Like fold but uses the FIRST element as the initial value:
val nums = List(1, 2, 3, 4, 5)
nums.reduceLeft(_ + _) // 15
nums.reduceLeft(_ max _) // 5
List.empty[Int].reduceLeft(_ + _) // throws — no initial!
Use when there's no natural "empty" value AND you know the list is non-empty.
scanLeft — running totals
Like foldLeft, but returns ALL intermediate values:
val nums = List(1, 2, 3, 4, 5)
nums.scanLeft(0)(_ + _)
// List(0, 1, 3, 6, 10, 15)
// ^ ^
// initial final
//
// every step shown
Useful for cumulative sums, running averages, prefix arrays.
Common patterns
// Group by key
val users = List("Ada", "Bob", "Alice", "Brad")
users.foldLeft(Map.empty[Char, List[String]]) { (acc, name) =>
val key = name.head
acc.updated(key, name :: acc.getOrElse(key, Nil))
}
// Count occurrences
List(1, 1, 2, 3, 1, 2).foldLeft(Map.empty[Int, Int].withDefaultValue(0)) {
(acc, n) => acc.updated(n, acc(n) + 1)
}
// Map(1 -> 3, 2 -> 2, 3 -> 1)
// Build a string
List("a", "b", "c").foldLeft("")((s, c) => s + c) // "abc"
// Find max with index
List(3, 1, 4, 1, 5, 9, 2, 6).zipWithIndex.foldLeft((0, Int.MinValue)) {
case ((bestIdx, bestVal), (n, i)) =>
if (n > bestVal) (i, n) else (bestIdx, bestVal)
}
sum, product, max, min — shortcuts
For common cases, Scala provides direct methods:
List(1, 2, 3).sum // 6
List(1, 2, 3).product // 6
List(1, 2, 3).max // 3
List(1, 2, 3).min // 1
Built on fold internally. Use these when applicable; fold for custom logic.
Common mistakes
- Wrong initial value —
foldLeft(0)(_ * _)gives 0 forever. For multiplication, use 1. - foldRight on huge lists — stack overflow. Convert to foldLeft + reverse, or use
iterator.foldLeft. - Forgetting reduceLeft throws on empty — use
reduceLeftOptionfor safety, or fall back to fold with explicit initial. - Mutating from inside fold — fold should be PURE. Mutation defeats the abstraction; use a regular loop instead.
- Confusing scan with fold — fold returns one value; scan returns the sequence of all intermediate accumulators.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…