Most data shaping in Dart and Flutter is a chain of iterable methods, and laziness explains surprising behavior.
List and Set are Iterables, as are map.keys, map.values and map.entries. Iterable offers a rich set of methods that take functions:
map(f)— transform each element.where(test)— keep elements matching a condition;whereType<T>()filters by type.expand(f)— map each element to several and flatten.fold(initial, combine)andreduce(combine)— combine into one value.any,every,contains,firstWhere(test, orElse: ...).take,skip,takeWhile,skipWhile.join(', '),toList(),toSet().
Key fact: map, where, expand and friends are lazy. They return an Iterable view that runs the function each time it is iterated. If you iterate twice, the function runs twice; if you never iterate, it never runs. Call .toList() when you need a concrete, reusable result or a List type (Flutter's children requires a List<Widget>).
package:collection adds helpers such as firstWhereOrNull, groupBy, sortedBy and deep equality. In Dart 3 the core library also has firstOrNull, lastOrNull and indexed (pairs of index and element as records).
sort mutates the list in place and returns void, so it can't be chained; copy first if you need the original order.
Example
void main() {
final words = ['dart', 'is', 'fun', 'and', 'fast'];
final lengths = words.map((w) => w.length); // lazy Iterable<int>
print(lengths.toList()); // [4, 2, 3, 3, 4]
final total = lengths.fold(0, (sum, n) => sum + n);
print(total); // 16
print(words.where((w) => w.startsWith('f')).join(' ')); // fun fast
print(words.any((w) => w.length > 3)); // true
print([[1, 2], [3]].expand((l) => l).toList()); // [1, 2, 3]
var calls = 0;
final upper = words.map((w) { calls++; return w.toUpperCase(); });
upper.first; upper.first;
print(calls); // 2 (lazy, re-run)
for (final (i, w) in words.take(2).indexed) {
print('$i:$w'); // 0:dart 1:is
}
}Remember
map/whereare lazy views — calltoList()to materializefoldcombines with an initial value;reduceneeds a non-empty iterablesortmutates in place and returns void
Watch out for
- Passing
items.map(...)where aListis required, or iterating an expensive lazy chain many times.