From af680e871dd7ebe967ce9fa950e4ab48ab557f46 Mon Sep 17 00:00:00 2001 From: Paul Taylor Date: Mon, 9 Oct 2017 18:30:21 -0700 Subject: [PATCH 1/2] feat(zip): make zip work on a variable number of source Iterables/AsyncIterables breaking change: zip selectors now take a single "values" Array argument, instead of varargs --- src/add/asynciterable-operators/zip.ts | 27 ++++++++-- src/add/iterable-operators/zip.ts | 27 ++++++++-- src/asynciterable/zip.ts | 70 +++++++++++++++++--------- src/iterable/zip.ts | 62 ++++++++++++++++------- 4 files changed, 134 insertions(+), 52 deletions(-) diff --git a/src/add/asynciterable-operators/zip.ts b/src/add/asynciterable-operators/zip.ts index 6d532176..9adcf955 100644 --- a/src/add/asynciterable-operators/zip.ts +++ b/src/add/asynciterable-operators/zip.ts @@ -4,11 +4,28 @@ import { zip } from '../../asynciterable/zip'; /** * @ignore */ -export function zipProto( - this: AsyncIterableX, - second: AsyncIterable, - selector: (fst: T, snd: T) => TResult | Promise): AsyncIterableX { - return zip(this, second, selector); +/* tslint:disable:max-line-length */ +export function zipProto(this: AsyncIterableX, source2: AsyncIterable): AsyncIterableX<[T, T2]>; +export function zipProto(this: AsyncIterableX, source2: AsyncIterable, source3: AsyncIterable): AsyncIterableX<[T, T2, T3]>; +export function zipProto(this: AsyncIterableX, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable): AsyncIterableX<[T, T2, T3, T4]>; +export function zipProto(this: AsyncIterableX, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable): AsyncIterableX<[T, T2, T3, T4, T5]>; +export function zipProto(this: AsyncIterableX, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable, source6: AsyncIterable): AsyncIterableX<[T, T2, T3, T4, T5, T6]>; + +export function zipProto(this: AsyncIterableX, project: (values: [T]) => R): AsyncIterableX; +export function zipProto(this: AsyncIterableX, project: (values: [T, T2]) => R, source2: AsyncIterable): AsyncIterableX; +export function zipProto(this: AsyncIterableX, project: (values: [T, T2, T3]) => R, source2: AsyncIterable, source3: AsyncIterable): AsyncIterableX; +export function zipProto(this: AsyncIterableX, project: (values: [T, T2, T3, T4]) => R, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable): AsyncIterableX; +export function zipProto(this: AsyncIterableX, project: (values: [T, T2,T3, T4, T5]) => R, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable): AsyncIterableX; +export function zipProto(this: AsyncIterableX, project: (values: [T, T2, T3, T4, T5, T6]) => R, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable, source6: AsyncIterable): AsyncIterableX; + +export function zipProto(this: AsyncIterableX, ...sources: AsyncIterable[]): AsyncIterableX; +export function zipProto(this: AsyncIterableX, project: (values: T[]) => R, ...sources: AsyncIterable[]): AsyncIterableX; +/* tslint:enable:max-line-length */ +export function zipProto(this: AsyncIterableX, ...args: any[]): AsyncIterableX { + let [arg1, ...sources] = args; + sources = (typeof arg1 === 'function') ? + [this, ...sources] : (arg1 = this) && args; + return zip(arg1, ...sources); } AsyncIterableX.prototype.zip = zipProto; diff --git a/src/add/iterable-operators/zip.ts b/src/add/iterable-operators/zip.ts index 3cc1c32b..e1686bdd 100644 --- a/src/add/iterable-operators/zip.ts +++ b/src/add/iterable-operators/zip.ts @@ -4,11 +4,28 @@ import { zip } from '../../iterable/zip'; /** * @ignore */ -export function zipProto( - this: IterableX, - second: Iterable, - fn: (fst: T, snd: T) => TResult): IterableX { - return zip(this, second, fn); +/* tslint:disable:max-line-length */ +export function zipProto(this: IterableX, source2: Iterable): IterableX<[T, T2]>; +export function zipProto(this: IterableX, source2: Iterable, source3: Iterable): IterableX<[T, T2, T3]>; +export function zipProto(this: IterableX, source2: Iterable, source3: Iterable, source4: Iterable): IterableX<[T, T2, T3, T4]>; +export function zipProto(this: IterableX, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable): IterableX<[T, T2, T3, T4, T5]>; +export function zipProto(this: IterableX, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable, source6: Iterable): IterableX<[T, T2, T3, T4, T5, T6]>; + +export function zipProto(this: IterableX, project: (values: [T]) => R): IterableX; +export function zipProto(this: IterableX, project: (values: [T, T2]) => R, source2: Iterable): IterableX; +export function zipProto(this: IterableX, project: (values: [T, T2, T3]) => R, source2: Iterable, source3: Iterable): IterableX; +export function zipProto(this: IterableX, project: (values: [T, T2, T3, T4]) => R, source2: Iterable, source3: Iterable, source4: Iterable): IterableX; +export function zipProto(this: IterableX, project: (values: [T, T2,T3, T4, T5]) => R, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable): IterableX; +export function zipProto(this: IterableX, project: (values: [T, T2, T3, T4, T5, T6]) => R, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable, source6: Iterable): IterableX; + +export function zipProto(this: IterableX, ...sources: Iterable[]): IterableX; +export function zipProto(this: IterableX, project: (values: T[]) => R, ...sources: Iterable[]): IterableX; +/* tslint:enable:max-line-length */ +export function zipProto(this: IterableX, ...args: any[]): IterableX { + let [arg1, ...sources] = args; + sources = (typeof arg1 === 'function') ? + [this, ...sources] : (arg1 = this) && args; + return zip(arg1, ...sources) as IterableX; } IterableX.prototype.zip = zipProto; diff --git a/src/asynciterable/zip.ts b/src/asynciterable/zip.ts index bbba1922..f3536bee 100644 --- a/src/asynciterable/zip.ts +++ b/src/asynciterable/zip.ts @@ -1,38 +1,58 @@ import { AsyncIterableX } from '../asynciterable'; +import { identityAsync } from '../internal/identity'; +import { returnAsyncIterator } from '../internal/returniterator'; -class ZipIterable extends AsyncIterableX { - private _left: AsyncIterable; - private _right: AsyncIterable; - private _fn: (left: TSource, right: TSource) => TResult | Promise; +class ZipAsyncIterable extends AsyncIterableX { + private _sources: AsyncIterable[]; + private _fn: (values: any[]) => TResult | Promise; - constructor( - left: AsyncIterable, - right: AsyncIterable, - fn: (left: TSource, right: TSource) => TResult | Promise) { + constructor(sources: AsyncIterable[], fn: (values: any[]) => TResult | Promise) { super(); - this._left = left; - this._right = right; + this._sources = sources; this._fn = fn; } async *[Symbol.asyncIterator]() { - const it1 = this._left[Symbol.asyncIterator](); - const it2 = this._right[Symbol.asyncIterator](); - while (1) { - const xs = await Promise.all([it1.next(), it2.next()]); - const [next1, next2] = xs; - if (!next1.done && !next2.done) { - yield await this._fn(next1.value, next2.value); - } else { - break; + const fn = this._fn; + const sourcesLength = this._sources.length; + const its = this._sources.map((x) => x[Symbol.asyncIterator]()); + do { + const values = new Array(sourcesLength); + for (let i = -1; ++i < sourcesLength;) { + const result = await its[i].next(); + if (result.done) { + await Promise.all(its.map(returnAsyncIterator)); + return; + } + values[i] = result.value; } - } + yield await fn(values); + } while (1); } } -export function zip( - left: AsyncIterable, - right: AsyncIterable, - fn: (left: TSource, right: TSource) => TResult | Promise): AsyncIterableX { - return new ZipIterable(left, right, fn); +/* tslint:disable:max-line-length */ +export function zip(source: AsyncIterable, source2: AsyncIterable): AsyncIterableX<[T, T2]>; +export function zip(source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable): AsyncIterableX<[T, T2, T3]>; +export function zip(source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable): AsyncIterableX<[T, T2, T3, T4]>; +export function zip(source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable): AsyncIterableX<[T, T2, T3, T4, T5]>; +export function zip(source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable, source6: AsyncIterable): AsyncIterableX<[T, T2, T3, T4, T5, T6]>; + +export function zip(project: (values: [T]) => R | Promise, source: AsyncIterable): AsyncIterableX; +export function zip(project: (values: [T, T2]) => R | Promise, source: AsyncIterable, source2: AsyncIterable): AsyncIterableX; +export function zip(project: (values: [T, T2, T3]) => R | Promise, source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable): AsyncIterableX; +export function zip(project: (values: [T, T2, T3, T4]) => R | Promise, source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable): AsyncIterableX; +export function zip(project: (values: [T, T2,T3, T4, T5]) => R | Promise, source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable): AsyncIterableX; +export function zip(project: (values: [T, T2, T3, T4, T5, T6]) => R | Promise, source: AsyncIterable, source2: AsyncIterable, source3: AsyncIterable, source4: AsyncIterable, source5: AsyncIterable, source6: AsyncIterable): AsyncIterableX; + +export function zip(...sources: AsyncIterable[]): AsyncIterableX; +export function zip(project: (values: T[]) => R | Promise, ...sources: AsyncIterable[]): AsyncIterableX; +/* tslint:enable:max-line-length */ +export function zip(...sources: any[]): AsyncIterableX { + let fn = sources.shift() as (values: any[]) => R | Promise; + if (typeof fn !== 'function') { + sources.push(fn); + fn = identityAsync; + } + return new ZipAsyncIterable(sources as AsyncIterable[], fn); } diff --git a/src/iterable/zip.ts b/src/iterable/zip.ts index 890efec4..9d1ba52d 100644 --- a/src/iterable/zip.ts +++ b/src/iterable/zip.ts @@ -1,29 +1,57 @@ import { IterableX } from '../iterable'; +import { identity } from '../internal/identity'; +import { returnIterator } from '../internal/returniterator'; class ZipIterable extends IterableX { - private _left: Iterable; - private _right: Iterable; - private _fn: (left: TSource, right: TSource) => TResult; + private _sources: Iterable[]; + private _fn: (values: any[]) => TResult; - constructor(left: Iterable, right: Iterable, fn: (left: TSource, right: TSource) => TResult) { + constructor(sources: Iterable[], fn: (values: any[]) => TResult) { super(); - this._left = left; - this._right = right; + this._sources = sources; this._fn = fn; } - *[Symbol.iterator]() { - const it1 = this._left[Symbol.iterator](), it2 = this._right[Symbol.iterator](); - let next1, next2; - while (!(next1 = it1.next()).done && (!(next2 = it2.next()).done)) { - yield this._fn(next1.value, next2.value); - } + const fn = this._fn; + const sourcesLength = this._sources.length; + const its = this._sources.map((x) => x[Symbol.iterator]()); + do { + const values = new Array(sourcesLength); + for (let index = -1; ++index < sourcesLength;) { + const result = its[index].next(); + if (result.done) { + its.forEach(returnIterator); + return; + } + values[index] = result.value; + } + yield fn(values); + } while (1); } } -export function zip( - left: Iterable, - right: Iterable, - fn: (left: TSource, right: TSource) => TResult): IterableX { - return new ZipIterable(left, right, fn); +/* tslint:disable:max-line-length */ +export function zip(source: Iterable, source2: Iterable): IterableX<[T, T2]>; +export function zip(source: Iterable, source2: Iterable, source3: Iterable): IterableX<[T, T2, T3]>; +export function zip(source: Iterable, source2: Iterable, source3: Iterable, source4: Iterable): IterableX<[T, T2, T3, T4]>; +export function zip(source: Iterable, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable): IterableX<[T, T2, T3, T4, T5]>; +export function zip(source: Iterable, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable, source6: Iterable): IterableX<[T, T2, T3, T4, T5, T6]>; + +export function zip(project: (values: [T]) => R, source: Iterable): IterableX; +export function zip(project: (values: [T, T2]) => R, source: Iterable, source2: Iterable): IterableX; +export function zip(project: (values: [T, T2, T3]) => R, source: Iterable, source2: Iterable, source3: Iterable): IterableX; +export function zip(project: (values: [T, T2, T3, T4]) => R, source: Iterable, source2: Iterable, source3: Iterable, source4: Iterable): IterableX; +export function zip(project: (values: [T, T2,T3, T4, T5]) => R, source: Iterable, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable): IterableX; +export function zip(project: (values: [T, T2, T3, T4, T5, T6]) => R, source: Iterable, source2: Iterable, source3: Iterable, source4: Iterable, source5: Iterable, source6: Iterable): IterableX; + +export function zip(...sources: Iterable[]): IterableX; +export function zip(project: (values: T[]) => R, ...sources: Iterable[]): IterableX; +/* tslint:enable:max-line-length */ +export function zip(...sources: any[]): IterableX { + let fn = sources.shift() as (values: any[]) => R; + if (typeof fn !== 'function') { + sources.unshift(fn); + fn = identity; + } + return new ZipIterable(sources as Iterable[], fn); } From 9a0703ac7282a4eed3596030c0e11ed696ef6761 Mon Sep 17 00:00:00 2001 From: Paul Taylor Date: Mon, 9 Oct 2017 18:31:32 -0700 Subject: [PATCH 2/2] test(zip): update zip tests for variable sources --- spec/asynciterable-operators/memoize-spec.ts | 6 ++--- spec/asynciterable-operators/publish-spec.ts | 2 +- spec/asynciterable-operators/share-spec.ts | 2 +- spec/asynciterable-operators/zip-spec.ts | 26 +++++++++++++++----- spec/iterable-operators/memoize-spec.ts | 6 ++--- spec/iterable-operators/publish-spec.ts | 2 +- spec/iterable-operators/share-spec.ts | 2 +- spec/iterable-operators/zip-spec.ts | 26 +++++++++++++++----- 8 files changed, 50 insertions(+), 22 deletions(-) diff --git a/spec/asynciterable-operators/memoize-spec.ts b/spec/asynciterable-operators/memoize-spec.ts index ee694569..6e8c1285 100644 --- a/spec/asynciterable-operators/memoize-spec.ts +++ b/spec/asynciterable-operators/memoize-spec.ts @@ -179,7 +179,7 @@ async function* rand() { test('AsyncIterable#memoize should share effects of random', async t => { const rnd = memoize(take(rand(), 100)); - t.true(await every(zip(rnd, rnd, async (l, r) => l === r), async x => x)); + t.true(await every(zip(async ([l, r]) => l === r, rnd, rnd), async x => x)); t.end(); }); @@ -189,7 +189,7 @@ test('AsyncIterable#memoize with selector', async t => { memoize( tap(range(0, 4), { next: async () => { n++; } }), undefined, - xs => take(zip(xs, xs, async (l, r) => l + r), 4) + xs => take(zip(async ([l, r]) => l + r, xs, xs), 4) ) ); @@ -204,7 +204,7 @@ test('AsyncIterable#memoize limited with selector', async t => { memoize( tap(range(0, 4), { next: async () => { n++; } }), 2, - xs => take(zip(xs, xs, async (l, r) => l + r), 4) + xs => take(zip(async ([l, r]) => l + r, xs, xs), 4) ) ); diff --git a/spec/asynciterable-operators/publish-spec.ts b/spec/asynciterable-operators/publish-spec.ts index 6501d316..ad2b5206 100644 --- a/spec/asynciterable-operators/publish-spec.ts +++ b/spec/asynciterable-operators/publish-spec.ts @@ -163,7 +163,7 @@ test('AsyncIterable#publish with selector', async t => { const res = await toArray( publish( tap(range(0, 10), { next: async () => { n++; } }), - xs => take(zip(xs, xs, async (l, r) => l + r), 4) + xs => take(zip(async ([l, r]) => l + r, xs, xs), 4) ) ); diff --git a/spec/asynciterable-operators/share-spec.ts b/spec/asynciterable-operators/share-spec.ts index 44e4686e..47f8bd63 100644 --- a/spec/asynciterable-operators/share-spec.ts +++ b/spec/asynciterable-operators/share-spec.ts @@ -59,7 +59,7 @@ test('AsyncIterable#share with selector', async t => { const res = await toArray( share( tap(range(0, 10), { next: async () => { n++;} }), - xs => take(zip(xs, xs, (l, r) => l + r), 4) + xs => take(zip(([l, r]) => l + r, xs, xs), 4) ) ); diff --git a/spec/asynciterable-operators/zip-spec.ts b/spec/asynciterable-operators/zip-spec.ts index 49ded5f8..a45b8ce5 100644 --- a/spec/asynciterable-operators/zip-spec.ts +++ b/spec/asynciterable-operators/zip-spec.ts @@ -8,7 +8,7 @@ import { hasNext, noNext } from '../asynciterablehelpers'; test('AsyncIterable#zip equal length', async t => { const xs = of(1, 2, 3); const ys = of(4, 5, 6); - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.asyncIterator](); await hasNext(t, it, 1 * 4); @@ -21,7 +21,7 @@ test('AsyncIterable#zip equal length', async t => { test('AsyncIterable#zip left longer', async t => { const xs = of(1, 2, 3, 4); const ys = of(4, 5, 6); - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.asyncIterator](); await hasNext(t, it, 1 * 4); @@ -34,7 +34,7 @@ test('AsyncIterable#zip left longer', async t => { test('AsyncIterable#zip right longer', async t => { const xs = of(1, 2, 3); const ys = of(4, 5, 6, 7); - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.asyncIterator](); await hasNext(t, it, 1 * 4); @@ -44,11 +44,25 @@ test('AsyncIterable#zip right longer', async t => { t.end(); }); +test('AsyncIterable#zip multiple sources', async t => { + const xs = of(1, 2, 3); + const ys = of(4, 5, 6, 7); + const zs = of(8, 9, 10); + const res = zip(([x, y, z]) => x * y * z, xs, ys, zs); + + const it = res[Symbol.asyncIterator](); + await hasNext(t, it, 1 * 4 * 8); + await hasNext(t, it, 2 * 5 * 9); + await hasNext(t, it, 3 * 6 * 10); + await noNext(t, it); + t.end(); +}); + test('AsyncIterable#zip left throws', async t => { const err = new Error(); const xs = _throw(err); const ys = of(4, 5, 6); - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.asyncIterator](); try { @@ -63,7 +77,7 @@ test('AsyncIterable#zip right throws', async t => { const err = new Error(); const xs = of(1, 2, 3); const ys = _throw(err); - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.asyncIterator](); try { @@ -78,7 +92,7 @@ test('AsyncIterable#zip selector throws', async t => { const err = new Error(); const xs = of(1, 2, 3); const ys = of(4, 5, 6); - const res = zip(xs, ys, (x, y) => { if (x > 0) { throw err; } return x * y; }); + const res = zip(([x, y]) => { if (x > 0) { throw err; } return x * y; }, xs, ys); const it = res[Symbol.asyncIterator](); try { diff --git a/spec/iterable-operators/memoize-spec.ts b/spec/iterable-operators/memoize-spec.ts index d6ff9992..7900b1a5 100644 --- a/spec/iterable-operators/memoize-spec.ts +++ b/spec/iterable-operators/memoize-spec.ts @@ -166,7 +166,7 @@ function* rand() { test('Iterable#memoize should share effects of random', t => { const rnd = memoize(take(rand(), 100)); - t.true(every(zip(rnd, rnd, (l, r) => l === r), x => x)); + t.true(every(zip(([l, r]) => l === r, rnd, rnd), x => x)); t.end(); }); @@ -176,7 +176,7 @@ test('Iterable#memoize with selector', t => { memoize( tap(range(0, 4), { next: () => n++ }), undefined, - xs => take(zip(xs, xs, (l, r) => l + r), 4) + xs => take(zip(([l, r]) => l + r, xs, xs), 4) ) ); @@ -191,7 +191,7 @@ test('Iterable#memoize limited with selector', t => { memoize( tap(range(0, 4), { next: () => n++ }), 2, - xs => take(zip(xs, xs, (l, r) => l + r), 4) + xs => take(zip(([l, r]) => l + r, xs, xs), 4) ) ); diff --git a/spec/iterable-operators/publish-spec.ts b/spec/iterable-operators/publish-spec.ts index 9eabf2f4..7845f368 100644 --- a/spec/iterable-operators/publish-spec.ts +++ b/spec/iterable-operators/publish-spec.ts @@ -154,7 +154,7 @@ test('Iterable#publish with selector', t => { const res = toArray( publish( tap(range(0, 10), { next: () => n++ }), - xs => take(zip(xs, xs, (l, r) => l + r), 4) + xs => take(zip(([l, r]) => l + r, xs, xs), 4) ) ); diff --git a/spec/iterable-operators/share-spec.ts b/spec/iterable-operators/share-spec.ts index 10341b72..0dca40fa 100644 --- a/spec/iterable-operators/share-spec.ts +++ b/spec/iterable-operators/share-spec.ts @@ -59,7 +59,7 @@ test('Iterable#share with selector', t => { const res = toArray( share( tap(range(0, 10), { next: () => n++ }), - xs => take(zip(xs, xs, (l, r) => l + r), 4) + xs => take(zip(([l, r]) => l + r, xs, xs), 4) ) ); diff --git a/spec/iterable-operators/zip-spec.ts b/spec/iterable-operators/zip-spec.ts index 96a26488..b8aa4441 100644 --- a/spec/iterable-operators/zip-spec.ts +++ b/spec/iterable-operators/zip-spec.ts @@ -7,7 +7,7 @@ import { hasNext, noNext } from '../iterablehelpers'; test('Iterable#zip equal length', t => { const xs = [1, 2, 3]; const ys = [4, 5, 6]; - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.iterator](); hasNext(t, it, 1 * 4); @@ -20,7 +20,7 @@ test('Iterable#zip equal length', t => { test('Iterable#zip left longer', t => { const xs = [1, 2, 3, 4]; const ys = [4, 5, 6]; - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.iterator](); hasNext(t, it, 1 * 4); @@ -33,7 +33,7 @@ test('Iterable#zip left longer', t => { test('Iterable#zip right longer', t => { const xs = [1, 2, 3]; const ys = [4, 5, 6, 7]; - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.iterator](); hasNext(t, it, 1 * 4); @@ -43,10 +43,24 @@ test('Iterable#zip right longer', t => { t.end(); }); +test('Iterable#zip multiple sources', t => { + const xs = [1, 2, 3]; + const ys = [4, 5, 6, 7]; + const zs = [8, 9, 10]; + const res = zip(([x, y, z]) => x * y * z, xs, ys, zs); + + const it = res[Symbol.iterator](); + hasNext(t, it, 1 * 4 * 8); + hasNext(t, it, 2 * 5 * 9); + hasNext(t, it, 3 * 6 * 10); + noNext(t, it); + t.end(); +}); + test('Iterable#zip left throws', t => { const xs = _throw(new Error()); const ys = [4, 5, 6]; - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.iterator](); t.throws(() => it.next()); @@ -56,7 +70,7 @@ test('Iterable#zip left throws', t => { test('Iterable#zip right throws', t => { const xs = [1, 2, 3]; const ys = _throw(new Error()); - const res = zip(xs, ys, (x, y) => x * y); + const res = zip(([x, y]) => x * y, xs, ys); const it = res[Symbol.iterator](); t.throws(() => it.next()); @@ -66,7 +80,7 @@ test('Iterable#zip right throws', t => { test('Iterable#zip selector throws', t => { const xs = [1, 2, 3]; const ys = [4, 5, 6]; - const res = zip(xs, ys, (x, y) => { if (x > 0) { throw new Error(); } return x * y; }); + const res = zip(([x, y]) => { if (x > 0) { throw new Error(); } return x * y; }, xs, ys); const it = res[Symbol.iterator](); t.throws(() => it.next());