scan
A lazy running accumulation — like reduce, but it yields every intermediate value instead of only the last.
Lecture
scan is reduce/fold with its
intermediate steps exposed: instead of collapsing an iterable down to
one final value, it emits every running accumulation, including
the seed itself as the first value. That first-value-is-the-seed detail
matters — scan(f, 0, [1, 2, 3]) yields four values
(0, then three running sums), not three.
scan1 is the unseeded variant, ported from FxTS's
scan(f, iterable) overload (no seed argument). It uses the
first element of the iterable as the initial accumulator and yields it
immediately, then keeps folding the rest — mirroring reduce's
relationship to fold. On an empty iterable, scan1
has no first element to seed with, so it yields nothing at all. Note
there is no chain method for scan1 (only scan is
on Fx/FxAsync) — call it data-first:
scan1(f, iterable).
Both are lazy: nothing runs until you pull. On the async side,
scanAsync/scan1Async still fold one step at a
time in order (each step needs the previous result), so
.concurrent(n) doesn't parallelize the fold itself — but it
does let an upstream fetch stage run concurrently, as long as the
accumulator function itself stays cheap. See Demo 2.
Demo 1 · Basics — scan and scan1
Demo 2 · Async, with concurrency upstream
The fold itself stays sequential, but the fetch that feeds it doesn't have to:
Try it yourself
Exercise: use scan to produce a running total of steps,
seeded at 0.
reduce/fold — collapse to one final value ·
flat — flatten nested iterables ·
peek — observe without transforming ·
concurrent — parallel evaluation