zipLongest<E> function

Iterable<List<E>> zipLongest<E>(
  1. Iterable<Iterable<E>> iterables,
  2. E fillValue
)

Like `zip` or `IterableZip` except that zip_longest stops only after the longest Iterable is exhausted instead of the shortest.

All Iterables shorter than the longest Iterable will be padded with fillValue.

If any of the input Iterables is infinitely long, the returned Iterable also will be infinitely long.

Implementation

// N.B.: It'd be nice if we could leverage [zip] or [IterableZip] by using the
// [Iterable.padRight] extension method, but doing so would require determining
// the length of the input [Iterable]s, which cannot work on ones that are
// infinitely long.
Iterable<List<E>> zipLongest<E>(
  Iterable<Iterable<E>> iterables,
  E fillValue,
) sync* {
  var iterators = [for (var iterable in iterables) iterable.iterator];

  while (true) {
    var exhaustedCount = 0;
    var current = <E>[];
    for (var i = 0; i < iterators.length; i += 1) {
      if (iterators[i].moveNext()) {
        current.add(iterators[i].current);
        continue;
      }

      exhaustedCount += 1;
      if (exhaustedCount == iterators.length) {
        return;
      }
      current.add(fillValue);
    }

    yield current;
  }
}