Iterables and Functional Collection Operations

Iterable operations are lazy until you consume them (toList, forEach, length, a for loop). List is an Iterable with indexed access.

final nums = [5, 3, 8, 1, 9, 2];

nums.map((n) => n * 2);                   // lazy Iterable
nums.where((n) => n.isEven).toList();     // filter
nums.fold<int>(0, (sum, n) => sum + n);   // reduce with an initial value
nums.reduce((a, b) => a > b ? a : b);     // max (throws on empty)
nums.any((n) => n > 8); nums.every((n) => n > 0);
nums.firstWhere((n) => n > 4, orElse: () => -1);
nums.lastWhere((n) => n < 5);
nums.singleWhere((n) => n == 8);
nums.take(3); nums.skip(2); nums.takeWhile((n) => n > 2); nums.skipWhile((n) => n > 2);
[[1, 2], [3]].expand((l) => l);           // flatMap
nums.followedBy([10, 11]);
nums.whereType<int>();
nums.toSet(); nums.toList(growable: false);
nums.asMap();                              // {0: 5, 1: 3, ...}
nums.indexed;                              // Iterable<(int, int)> records (Dart 3)
for (final (i, n) in nums.indexed) print('$i: $n');

// Chaining
final result = nums.where((n) => n > 2).map((n) => n * n).toList()..sort();

// Lazy evaluation
final lazy = Iterable.generate(1000000, (i) => i).where((i) => i % 7 == 0).take(3);
print(lazy.toList());                       // computes only what's needed

// package:collection extensions
import 'package
…

10.1 Custom Iterables

class Countdown extends Iterable<int> {
  final int start;
  Countdown(this.start);
  @override
  Iterator<int> get iterator => _CountdownIterator(start);
}

class _CountdownIterator implements Iterator<int> {
  int _current;
  _CountdownIterator(int start) : _current = start + 1;
  @override
  int get current => _current;
  @override
  bool moveNext() => --_current > 0;
}

for (final n in Countdown(3)) print(n);     // 3 2 1
Countdown(5).map((n) => n * 10).toList();