reduce
Collapses a pipeline into a single value, using its first element as the starting seed.
Lecture
reduce is a terminal operator: unlike
map or filter, calling it immediately pulls
every value through the whole lazy pipeline behind it and produces one
concrete result. Nothing upstream runs until you call a terminal like
this one.
This is the unseeded form: it takes the first element of the
iterable as the starting accumulator, then combines the rest into it.
Because of that, calling it on an empty iterable makes no sense — there's
no first element to seed with — so it throws a StateError.
FxTS overloads reduce for both the seeded and unseeded case
by argument count — reduce(f, iterable) vs.
reduce(f, seed, iterable). Dart has no arity-based
overloading, so FxDart keeps reduce for the unseeded form
and renames the seeded one to fold —
matching Dart's own Iterable.fold naming. If you have a seed,
reach for fold.
On the sync chain, Fx extends Iterable, so
.reduce(f) is simply Dart's built-in method — same contract,
same StateError on empty. On the async chain,
FxAsync.reduce is spelled out explicitly and awaits each
combine step.
Demo 1 · Basics & the empty-input error
Demo 2 · Async, with concurrency
reduce still pulls the whole pipeline behind it — including
a .concurrent(n) stage, which evaluates n
upstream values at a time while reduce combines them as they
arrive in order:
Try it yourself
Exercise: use reduce to find the longest word in the list.
fold — the seeded counterpart ·
reduceLazy — a reusable, curried reducer ·
sum — reduce specialized for numbers ·
concurrent — parallel evaluation upstream