flattened
Flattens nested iterables by a given depth — strings are left alone.
Lecture
flattened walks a nested structure of iterables and splices
inner elements into the outer sequence, up to depth levels
deep (default 1). Anything that is an Iterable
counts as "flattenable" except String — so
flattened(['ab', ['cd']]) keeps 'ab' intact instead
of exploding it into characters. flattened is the
Dart-idiomatic name; fxdart also accepts the FxTS spelling flat
— they're the same operator.
Why Iterable<dynamic>, and why that's okay:
TypeScript's flat has a DeepFlat conditional
type that can describe "the element type after flattening N levels."
Dart's type system has no equivalent mechanism — the input's nesting
shape isn't known until runtime, so there is no sound way to compute a
static element type. Rather than lie with a generic that doesn't hold,
the Dart port is honest about it and returns Iterable<dynamic>.
If you know the shape of what you're flattening and want a typed
result, reach for flatMap
instead: flatMap((row) => row, matrix) gives you a typed
flatten for exactly-one-level-deep, uniformly-shaped data.
Like flat in FxTS, flattenedAsync only recurses
into nesting that is already a synchronous Iterable
by the time it arrives — it does not await a Future buried
inside a nested collection. Combine it with an upstream
.map(...).concurrent(n) stage to fetch nested lists in
parallel, then let .flattened() splice the already-resolved
results together.
Demo 1 · Basics & depth
Demo 2 · Async, with concurrency
Fetch the (already nested) results concurrently, then flatten the resolved lists:
Try it yourself
Exercise: use flattened() to flatten scoreGroups
by one level.
flatMap — typed map + flatten in one step ·
map — transform without flattening ·
scan — running accumulation ·
concurrent — parallel evaluation