Skip to content

Commit 0c4d513

Browse files
trxcllntmattpodwysocki
authored andcommitted
Zip n sources (#73)
* 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 * test(zip): update zip tests for variable sources
1 parent 4098a8c commit 0c4d513

File tree

12 files changed

+184
-74
lines changed

12 files changed

+184
-74
lines changed

spec/asynciterable-operators/memoize-spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ async function* rand() {
179179

180180
test('AsyncIterable#memoize should share effects of random', async t => {
181181
const rnd = memoize(take(rand(), 100));
182-
t.true(await every(zip(rnd, rnd, async (l, r) => l === r), async x => x));
182+
t.true(await every(zip(async ([l, r]) => l === r, rnd, rnd), async x => x));
183183
t.end();
184184
});
185185

@@ -189,7 +189,7 @@ test('AsyncIterable#memoize with selector', async t => {
189189
memoize(
190190
tap(range(0, 4), { next: async () => { n++; } }),
191191
undefined,
192-
xs => take(zip(xs, xs, async (l, r) => l + r), 4)
192+
xs => take(zip(async ([l, r]) => l + r, xs, xs), 4)
193193
)
194194
);
195195

@@ -204,7 +204,7 @@ test('AsyncIterable#memoize limited with selector', async t => {
204204
memoize(
205205
tap(range(0, 4), { next: async () => { n++; } }),
206206
2,
207-
xs => take(zip(xs, xs, async (l, r) => l + r), 4)
207+
xs => take(zip(async ([l, r]) => l + r, xs, xs), 4)
208208
)
209209
);
210210

spec/asynciterable-operators/publish-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ test('AsyncIterable#publish with selector', async t => {
163163
const res = await toArray(
164164
publish(
165165
tap(range(0, 10), { next: async () => { n++; } }),
166-
xs => take(zip(xs, xs, async (l, r) => l + r), 4)
166+
xs => take(zip(async ([l, r]) => l + r, xs, xs), 4)
167167
)
168168
);
169169

spec/asynciterable-operators/share-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ test('AsyncIterable#share with selector', async t => {
5959
const res = await toArray(
6060
share(
6161
tap(range(0, 10), { next: async () => { n++;} }),
62-
xs => take(zip(xs, xs, (l, r) => l + r), 4)
62+
xs => take(zip(([l, r]) => l + r, xs, xs), 4)
6363
)
6464
);
6565

spec/asynciterable-operators/zip-spec.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { hasNext, noNext } from '../asynciterablehelpers';
88
test('AsyncIterable#zip equal length', async t => {
99
const xs = of(1, 2, 3);
1010
const ys = of(4, 5, 6);
11-
const res = zip(xs, ys, (x, y) => x * y);
11+
const res = zip(([x, y]) => x * y, xs, ys);
1212

1313
const it = res[Symbol.asyncIterator]();
1414
await hasNext(t, it, 1 * 4);
@@ -21,7 +21,7 @@ test('AsyncIterable#zip equal length', async t => {
2121
test('AsyncIterable#zip left longer', async t => {
2222
const xs = of(1, 2, 3, 4);
2323
const ys = of(4, 5, 6);
24-
const res = zip(xs, ys, (x, y) => x * y);
24+
const res = zip(([x, y]) => x * y, xs, ys);
2525

2626
const it = res[Symbol.asyncIterator]();
2727
await hasNext(t, it, 1 * 4);
@@ -34,7 +34,7 @@ test('AsyncIterable#zip left longer', async t => {
3434
test('AsyncIterable#zip right longer', async t => {
3535
const xs = of(1, 2, 3);
3636
const ys = of(4, 5, 6, 7);
37-
const res = zip(xs, ys, (x, y) => x * y);
37+
const res = zip(([x, y]) => x * y, xs, ys);
3838

3939
const it = res[Symbol.asyncIterator]();
4040
await hasNext(t, it, 1 * 4);
@@ -44,11 +44,25 @@ test('AsyncIterable#zip right longer', async t => {
4444
t.end();
4545
});
4646

47+
test('AsyncIterable#zip multiple sources', async t => {
48+
const xs = of(1, 2, 3);
49+
const ys = of(4, 5, 6, 7);
50+
const zs = of(8, 9, 10);
51+
const res = zip(([x, y, z]) => x * y * z, xs, ys, zs);
52+
53+
const it = res[Symbol.asyncIterator]();
54+
await hasNext(t, it, 1 * 4 * 8);
55+
await hasNext(t, it, 2 * 5 * 9);
56+
await hasNext(t, it, 3 * 6 * 10);
57+
await noNext(t, it);
58+
t.end();
59+
});
60+
4761
test('AsyncIterable#zip left throws', async t => {
4862
const err = new Error();
4963
const xs = _throw<number>(err);
5064
const ys = of(4, 5, 6);
51-
const res = zip(xs, ys, (x, y) => x * y);
65+
const res = zip(([x, y]) => x * y, xs, ys);
5266

5367
const it = res[Symbol.asyncIterator]();
5468
try {
@@ -63,7 +77,7 @@ test('AsyncIterable#zip right throws', async t => {
6377
const err = new Error();
6478
const xs = of(1, 2, 3);
6579
const ys = _throw<number>(err);
66-
const res = zip(xs, ys, (x, y) => x * y);
80+
const res = zip(([x, y]) => x * y, xs, ys);
6781

6882
const it = res[Symbol.asyncIterator]();
6983
try {
@@ -78,7 +92,7 @@ test('AsyncIterable#zip selector throws', async t => {
7892
const err = new Error();
7993
const xs = of(1, 2, 3);
8094
const ys = of(4, 5, 6);
81-
const res = zip(xs, ys, (x, y) => { if (x > 0) { throw err; } return x * y; });
95+
const res = zip(([x, y]) => { if (x > 0) { throw err; } return x * y; }, xs, ys);
8296

8397
const it = res[Symbol.asyncIterator]();
8498
try {

spec/iterable-operators/memoize-spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function* rand() {
166166

167167
test('Iterable#memoize should share effects of random', t => {
168168
const rnd = memoize(take(rand(), 100));
169-
t.true(every(zip(rnd, rnd, (l, r) => l === r), x => x));
169+
t.true(every(zip(([l, r]) => l === r, rnd, rnd), x => x));
170170
t.end();
171171
});
172172

@@ -176,7 +176,7 @@ test('Iterable#memoize with selector', t => {
176176
memoize(
177177
tap(range(0, 4), { next: () => n++ }),
178178
undefined,
179-
xs => take(zip(xs, xs, (l, r) => l + r), 4)
179+
xs => take(zip(([l, r]) => l + r, xs, xs), 4)
180180
)
181181
);
182182

@@ -191,7 +191,7 @@ test('Iterable#memoize limited with selector', t => {
191191
memoize(
192192
tap(range(0, 4), { next: () => n++ }),
193193
2,
194-
xs => take(zip(xs, xs, (l, r) => l + r), 4)
194+
xs => take(zip(([l, r]) => l + r, xs, xs), 4)
195195
)
196196
);
197197

spec/iterable-operators/publish-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ test('Iterable#publish with selector', t => {
154154
const res = toArray(
155155
publish(
156156
tap(range(0, 10), { next: () => n++ }),
157-
xs => take(zip(xs, xs, (l, r) => l + r), 4)
157+
xs => take(zip(([l, r]) => l + r, xs, xs), 4)
158158
)
159159
);
160160

spec/iterable-operators/share-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ test('Iterable#share with selector', t => {
5959
const res = toArray(
6060
share(
6161
tap(range(0, 10), { next: () => n++ }),
62-
xs => take(zip(xs, xs, (l, r) => l + r), 4)
62+
xs => take(zip(([l, r]) => l + r, xs, xs), 4)
6363
)
6464
);
6565

spec/iterable-operators/zip-spec.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { hasNext, noNext } from '../iterablehelpers';
77
test('Iterable#zip equal length', t => {
88
const xs = [1, 2, 3];
99
const ys = [4, 5, 6];
10-
const res = zip(xs, ys, (x, y) => x * y);
10+
const res = zip(([x, y]) => x * y, xs, ys);
1111

1212
const it = res[Symbol.iterator]();
1313
hasNext(t, it, 1 * 4);
@@ -20,7 +20,7 @@ test('Iterable#zip equal length', t => {
2020
test('Iterable#zip left longer', t => {
2121
const xs = [1, 2, 3, 4];
2222
const ys = [4, 5, 6];
23-
const res = zip(xs, ys, (x, y) => x * y);
23+
const res = zip(([x, y]) => x * y, xs, ys);
2424

2525
const it = res[Symbol.iterator]();
2626
hasNext(t, it, 1 * 4);
@@ -33,7 +33,7 @@ test('Iterable#zip left longer', t => {
3333
test('Iterable#zip right longer', t => {
3434
const xs = [1, 2, 3];
3535
const ys = [4, 5, 6, 7];
36-
const res = zip(xs, ys, (x, y) => x * y);
36+
const res = zip(([x, y]) => x * y, xs, ys);
3737

3838
const it = res[Symbol.iterator]();
3939
hasNext(t, it, 1 * 4);
@@ -43,10 +43,24 @@ test('Iterable#zip right longer', t => {
4343
t.end();
4444
});
4545

46+
test('Iterable#zip multiple sources', t => {
47+
const xs = [1, 2, 3];
48+
const ys = [4, 5, 6, 7];
49+
const zs = [8, 9, 10];
50+
const res = zip(([x, y, z]) => x * y * z, xs, ys, zs);
51+
52+
const it = res[Symbol.iterator]();
53+
hasNext(t, it, 1 * 4 * 8);
54+
hasNext(t, it, 2 * 5 * 9);
55+
hasNext(t, it, 3 * 6 * 10);
56+
noNext(t, it);
57+
t.end();
58+
});
59+
4660
test('Iterable#zip left throws', t => {
4761
const xs = _throw<number>(new Error());
4862
const ys = [4, 5, 6];
49-
const res = zip(xs, ys, (x, y) => x * y);
63+
const res = zip(([x, y]) => x * y, xs, ys);
5064

5165
const it = res[Symbol.iterator]();
5266
t.throws(() => it.next());
@@ -56,7 +70,7 @@ test('Iterable#zip left throws', t => {
5670
test('Iterable#zip right throws', t => {
5771
const xs = [1, 2, 3];
5872
const ys = _throw<number>(new Error());
59-
const res = zip(xs, ys, (x, y) => x * y);
73+
const res = zip(([x, y]) => x * y, xs, ys);
6074

6175
const it = res[Symbol.iterator]();
6276
t.throws(() => it.next());
@@ -66,7 +80,7 @@ test('Iterable#zip right throws', t => {
6680
test('Iterable#zip selector throws', t => {
6781
const xs = [1, 2, 3];
6882
const ys = [4, 5, 6];
69-
const res = zip(xs, ys, (x, y) => { if (x > 0) { throw new Error(); } return x * y; });
83+
const res = zip(([x, y]) => { if (x > 0) { throw new Error(); } return x * y; }, xs, ys);
7084

7185
const it = res[Symbol.iterator]();
7286
t.throws(() => it.next());

src/add/asynciterable-operators/zip.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@ import { zip } from '../../asynciterable/zip';
44
/**
55
* @ignore
66
*/
7-
export function zipProto<T, TResult>(
8-
this: AsyncIterableX<T>,
9-
second: AsyncIterable<T>,
10-
selector: (fst: T, snd: T) => TResult | Promise<TResult>): AsyncIterableX<TResult> {
11-
return zip(this, second, selector);
7+
/* tslint:disable:max-line-length */
8+
export function zipProto<T, T2>(this: AsyncIterableX<T>, source2: AsyncIterable<T2>): AsyncIterableX<[T, T2]>;
9+
export function zipProto<T, T2, T3>(this: AsyncIterableX<T>, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>): AsyncIterableX<[T, T2, T3]>;
10+
export function zipProto<T, T2, T3, T4>(this: AsyncIterableX<T>, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>): AsyncIterableX<[T, T2, T3, T4]>;
11+
export function zipProto<T, T2, T3, T4, T5>(this: AsyncIterableX<T>, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>, source5: AsyncIterable<T5>): AsyncIterableX<[T, T2, T3, T4, T5]>;
12+
export function zipProto<T, T2, T3, T4, T5, T6>(this: AsyncIterableX<T>, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>, source5: AsyncIterable<T5>, source6: AsyncIterable<T6>): AsyncIterableX<[T, T2, T3, T4, T5, T6]>;
13+
14+
export function zipProto<T, R>(this: AsyncIterableX<T>, project: (values: [T]) => R): AsyncIterableX<R>;
15+
export function zipProto<T, T2, R>(this: AsyncIterableX<T>, project: (values: [T, T2]) => R, source2: AsyncIterable<T2>): AsyncIterableX<R>;
16+
export function zipProto<T, T2, T3, R>(this: AsyncIterableX<T>, project: (values: [T, T2, T3]) => R, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>): AsyncIterableX<R>;
17+
export function zipProto<T, T2, T3, T4, R>(this: AsyncIterableX<T>, project: (values: [T, T2, T3, T4]) => R, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>): AsyncIterableX<R>;
18+
export function zipProto<T, T2, T3, T4, T5, R>(this: AsyncIterableX<T>, project: (values: [T, T2,T3, T4, T5]) => R, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>, source5: AsyncIterable<T5>): AsyncIterableX<R>;
19+
export function zipProto<T, T2, T3, T4, T5, T6, R>(this: AsyncIterableX<T>, project: (values: [T, T2, T3, T4, T5, T6]) => R, source2: AsyncIterable<T2>, source3: AsyncIterable<T3>, source4: AsyncIterable<T4>, source5: AsyncIterable<T5>, source6: AsyncIterable<T6>): AsyncIterableX<R>;
20+
21+
export function zipProto<T>(this: AsyncIterableX<T>, ...sources: AsyncIterable<T>[]): AsyncIterableX<T[]>;
22+
export function zipProto<T, R>(this: AsyncIterableX<T>, project: (values: T[]) => R, ...sources: AsyncIterable<T>[]): AsyncIterableX<R>;
23+
/* tslint:enable:max-line-length */
24+
export function zipProto<T, R>(this: AsyncIterableX<T>, ...args: any[]): AsyncIterableX<R> {
25+
let [arg1, ...sources] = args;
26+
sources = (typeof arg1 === 'function') ?
27+
[this, ...sources] : (arg1 = this) && args;
28+
return zip<T, R>(arg1, ...sources);
1229
}
1330

1431
AsyncIterableX.prototype.zip = zipProto;

src/add/iterable-operators/zip.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,28 @@ import { zip } from '../../iterable/zip';
44
/**
55
* @ignore
66
*/
7-
export function zipProto<T, TResult>(
8-
this: IterableX<T>,
9-
second: Iterable<T>,
10-
fn: (fst: T, snd: T) => TResult): IterableX<TResult> {
11-
return zip(this, second, fn);
7+
/* tslint:disable:max-line-length */
8+
export function zipProto<T, T2>(this: IterableX<T>, source2: Iterable<T2>): IterableX<[T, T2]>;
9+
export function zipProto<T, T2, T3>(this: IterableX<T>, source2: Iterable<T2>, source3: Iterable<T3>): IterableX<[T, T2, T3]>;
10+
export function zipProto<T, T2, T3, T4>(this: IterableX<T>, source2: Iterable<T2>, source3: Iterable<T3>, source4: Iterable<T4>): IterableX<[T, T2, T3, T4]>;
11+
export function zipProto<T, T2, T3, T4, T5>(this: IterableX<T>, source2: Iterable<T2>, source3: Iterable<T3>, source4: Iterable<T4>, source5: Iterable<T5>): IterableX<[T, T2, T3, T4, T5]>;
12+
export function zipProto<T, T2, T3, T4, T5, T6>(this: IterableX<T>, source2: Iterable<T2>, source3: Iterable<T3>, source4: Iterable<T4>, source5: Iterable<T5>, source6: Iterable<T6>): IterableX<[T, T2, T3, T4, T5, T6]>;
13+
14+
export function zipProto<T, R>(this: IterableX<T>, project: (values: [T]) => R): IterableX<R>;
15+
export function zipProto<T, T2, R>(this: IterableX<T>, project: (values: [T, T2]) => R, source2: Iterable<T2>): IterableX<R>;
16+
export function zipProto<T, T2, T3, R>(this: IterableX<T>, project: (values: [T, T2, T3]) => R, source2: Iterable<T2>, source3: Iterable<T3>): IterableX<R>;
17+
export function zipProto<T, T2, T3, T4, R>(this: IterableX<T>, project: (values: [T, T2, T3, T4]) => R, source2: Iterable<T2>, source3: Iterable<T3>, source4: Iterable<T4>): IterableX<R>;
18+
export function zipProto<T, T2, T3, T4, T5, R>(this: IterableX<T>, project: (values: [T, T2,T3, T4, T5]) => R, source2: Iterable<T2>, source3: Iterable<T3>, source4: Iterable<T4>, source5: Iterable<T5>): IterableX<R>;
19+
export function zipProto<T, T2, T3, T4, T5, T6, R>(this: IterableX<T>, project: (values: [T, T2, T3, T4, T5, T6]) => R, source2: Iterable<T2>, source3: Iterable<T3>, source4: Iterable<T4>, source5: Iterable<T5>, source6: Iterable<T6>): IterableX<R>;
20+
21+
export function zipProto<T>(this: IterableX<T>, ...sources: Iterable<T>[]): IterableX<T[]>;
22+
export function zipProto<T, R>(this: IterableX<T>, project: (values: T[]) => R, ...sources: Iterable<T>[]): IterableX<R>;
23+
/* tslint:enable:max-line-length */
24+
export function zipProto<T, R>(this: IterableX<T>, ...args: any[]): IterableX<R> {
25+
let [arg1, ...sources] = args;
26+
sources = (typeof arg1 === 'function') ?
27+
[this, ...sources] : (arg1 = this) && args;
28+
return zip<T, R>(arg1, ...sources) as IterableX<R>;
1229
}
1330

1431
IterableX.prototype.zip = zipProto;

0 commit comments

Comments
 (0)