2.0.0 • Published 7 years ago
zip-iterables v2.0.0
zip-iterables
This package provides:
- A
zipfunction that converts an array ofIterables into anIterableof arrays. zipAsyncandzipAsyncParallelfunctions that do the same forAsyncIterables.- TypeScript overloads for n-tuples, such as
<A, B>(Iterable<A>, Iterable<B>) => Iterable<[A, B]>. - Some utilities such as:
asyncIterableToArray()iterableToAsyncIterable()isAsyncIterable()andisIterable()iteratorReturn(),iteratorThrow(),asyncIteratorReturn()andasyncIteratorThrow()
Example
import { zip } from "zip-iterables";
Array.from(zip(["a", "b", "c"], ["d", "e"], [1, 2]));
// Result:
// [
// ['a', 'd', 1],
// ['b', 'e', 2]
// ]Why this package?
It is fairly trivial to implement a basic zip function:
// Example only. Do not do this in production.
function* zip<T>(...iterables: Iterable<T>[]): Iterable<T> {
const iters = iterables.map(x => x[Symbol.iterator]());
while (true) {
const ret = new Array<T>();
for (const iter of iters) {
const { done, value } = iter.next();
if (done) {
return;
}
ret.push(value);
}
yield ret;
}
}However, the functions provided by this package have a number of important advantages over a naive implementation:
- The resulting
IterableorAsyncIterablecan be looped over multiple times (i.e. it returns a fresh iterator in response to[Symbol.iterator]()and[Symbol.asyncIterator]()). This would not be the case ifzipitself is a generator function (as above). - All three of the
next,returnandthrowmethods, instead of justnext, are forwarded to the inner iterators and the results collated. - Return values (
valueof theIteratorResultwhendone = true) are also collated from inner iterators in addition to yielded values, withundefinedused as the value for iterators that have not finished. - As soon as
next,returnorthrowon one of the iterators either throws or returnsdone = true, the other iterators are closed by calling thereturnmethod, if defined. This gives the iterator an opportunity to free any resources so they do not leak. For example, if the iterator is a generator, this executes anyfinally {..}blocks around the currentyield. - If any of the iterators throw in response to
return, this does not preventreturnfrom being called on the other iterators. - If any of the iterators throw and an error has already been caught, the original error is re-thrown instead of the
new one. (This is what TypeScript and Babel do for a
for...ofloop.) - The
returnmethod is only called on iterators that have started (nextcalled at least once) but not finished (nexthas not returneddone = true) and not thrown. (This is what TypeScript and Babel do for afor...ofloop.) - Any input passed to the zipped iterator via the
next,returnandthrowmethods is forwarded to the individual iterators. - For
zipAsyncParallel, thenext,returnandthrowmethods of theAsyncIterators are executed in parallel to maximise throughput.