mapWithIndex & friends
The four index-aware operators — map, filter, flatMap and fold with the element's position as a second argument.
Lecture
zipWithIndex already gives
you the position: pair every element with its index, then read the pair.
That works, and it is the right tool when the pair itself is what you
want. When it isn't, you pay for a record per element and a callback body
written in p.$1 / p.$2 rather than names.
These four take the index directly instead. There is nothing to allocate and nothing to unpack, and the chain says what it does.
The index counts that stage's input. It is not the
element's position in the original source — a
filter above
mapWithIndex renumbers what survives it, starting from 0
again. filterWithIndex is the one to read twice: its count
advances across the elements it drops, because those are still
input. flatMapWithIndex counts source elements, not emitted
ones, so an inner iterable of five values still advances the index by one.
Every one has an …Async form, and the numbering survives
concurrent: it overlaps the
upstream pulls but still resolves them in order, so element n
gets index n whatever the latencies were. The counter also lives
per iteration, so re-running a chain starts again at 0.
One Dart wrinkle on foldWithIndex: an untyped accumulator
lambda infers Acc as Object? and the arithmetic
stops compiling. That is not new here — Dart's own
Iterable.fold behaves the same way — and the fix is the same:
write foldWithIndex<int>(…).
Demo 1 · mapWithIndex, and what it replaces
Demo 2 · filter, flatMap, fold — and async
Try it yourself
Exercise: number the finishers 1st, 2nd, 3rd using the index.