lilit
Version:
[![Build status][tr-svg]][travis]
681 lines • 17.4 kB
JavaScript
import { asyncTee, asyncTeeN, forAwaitableIterator } from './common.mjs';
// OPERATORS
export function map(f) {
return async function* (xs) {
for await (const x of xs)
yield f(x);
};
}
export function tap(f) {
return async function* (xs) {
for await (const x of xs) {
f(x);
yield x;
}
};
}
export const inspect = tap;
export function forEach(f) {
return async function (xs) {
for await (const x of xs)
f(x);
};
}
export const subscribe = forEach;
export function reduce(f, init) {
return async function (xs) {
let res = init;
for await (const x of xs) {
res = f(res, x);
}
return res;
};
}
export function scan(f, init) {
return async function* (xs) {
let res = init;
for await (const x of xs) {
res = f(res, x);
yield res;
}
};
}
export const reducutions = scan;
export function some(p) {
return async function (xs) {
for await (const x of xs) {
if (p(x))
return true;
}
return false;
};
}
export function every(p) {
return async function (xs) {
for await (const x of xs) {
if (!p(x))
return false;
}
return true;
};
}
export function filter(p) {
return async function* (xs) {
for await (const x of xs) {
if (p(x))
yield x;
}
};
}
export function partition(p) {
return function (xs) {
const [xs1, xs2] = asyncTee(xs);
return [filter(p)(xs1), filter((x) => !p(x))(xs2)];
};
}
export function skip(n) {
return async function* (xs) {
let i = 0;
for await (const x of xs) {
if (++i <= n)
continue;
yield x;
}
};
}
export function take(n) {
return async function* (xs) {
let i = 0;
for await (const x of xs) {
if (++i > n)
break;
yield x;
}
};
}
// TODO: rename?
export function partitionAt(n) {
return function (xs) {
const [xs1, xs2] = asyncTee(xs);
return [take(n)(xs1), skip(n)(xs2)];
};
}
export const splitAt = partitionAt;
export function skipWhile(f) {
return async function* (xs) {
const it = forAwaitableIterator(xs);
let first;
for await (const x of it) {
first = x;
if (!f(x))
break;
}
yield first;
for await (const x of it)
yield x;
};
}
export function takeWhile(f) {
return async function* (xs) {
for await (const x of xs) {
if (f(x))
yield x;
else
break;
}
};
}
export function partitionWhile(f) {
return function (xs) {
const [xs1, xs2] = asyncTee(xs);
return [takeWhile(f)(xs1), skipWhile(f)(xs2)];
};
}
export function find(p) {
return async function (xs) {
for await (const x of xs) {
if (p(x))
return x;
}
return null;
};
}
export function findIndex(p) {
return async function (xs) {
let i = 0;
for await (const x of xs) {
if (p(x))
return i;
i++;
}
return -1;
};
}
export function pluck(key) {
return async function* (xs) {
for await (const x of xs)
yield x[key];
};
}
// like pluck, but accepts an iterable of keys
export function select(keys) {
return async function* (xs) {
for await (const x of xs) {
let r = x;
for (const k of keys) {
r = r != null ? r[k] : undefined;
}
yield r;
}
};
}
export function unzip2() {
return function (xs) {
const [xs1, xs2] = asyncTee(xs);
return [pluck(0)(xs1), pluck(1)(xs2)];
};
}
export function unzip3() {
return function (xs) {
const [xs1, xs2, xs3] = asyncTeeN(xs, 3);
return [pluck(0)(xs1), pluck(1)(xs2), pluck(2)(xs3)];
};
}
export function unzip(n = 2) {
return function (xs) {
const xss = asyncTeeN(xs, n);
return xss.map((xs, i) => pluck(i)(xs));
};
}
export function groupBy(f) {
return async function (xs) {
const res = new Map();
for await (const x of xs) {
const key = f(x);
if (!res.has(key))
res.set(key, []);
res.get(key).push(x);
}
return res;
};
}
export function groupByKey(key) {
return groupBy((x) => x[key]);
}
export function mapKeys(f) {
return async function* (xs) {
for await (const [k, v] of xs)
yield [f(k), v];
};
}
export function mapValues(f) {
return async function* (xs) {
for await (const [k, v] of xs)
yield [k, f(v)];
};
}
export function pairwise() {
return async function* (xs) {
const it = forAwaitableIterator(xs);
let prev = (await it.next()).value;
for await (const x of it) {
yield [prev, x];
prev = x;
}
};
}
export function length() {
return async function (xs) {
let c = 0;
for await (const _ of xs)
c++;
return c;
};
}
export function min() {
return async function (xs) {
let res = Number.POSITIVE_INFINITY;
for await (const x of xs) {
if (x < res)
res = x;
}
return res;
};
}
export function max() {
return async function (xs) {
let res = Number.NEGATIVE_INFINITY;
for await (const x of xs) {
if (x > res)
res = x;
}
return res;
};
}
export function minMax() {
return async function (xs) {
let min = Number.POSITIVE_INFINITY;
let max = Number.NEGATIVE_INFINITY;
for await (const x of xs) {
if (x < min)
min = x;
if (x > max)
max = x;
}
return [min, max];
};
}
export function minBy(cf) {
return async function (xs) {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done)
return null;
let res = value;
for await (const x of it)
if (cf(x, res) < 0)
res = x;
return res;
};
}
export function maxBy(cf) {
return async function (xs) {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done)
return null;
let res = value;
for await (const x of it)
if (cf(x, res) > 0)
res = x;
return res;
};
}
export function minMaxBy(cf) {
return async function (xs) {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done)
return [null, null];
let min = value;
let max = value;
for await (const x of it) {
if (cf(x, min) < 0)
min = x;
if (cf(x, max) > 0)
max = x;
}
return [min, max];
};
}
export function minByScan(cf) {
return async function* (xs) {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done)
yield null;
let res = value;
for await (const x of it) {
if (cf(x, res) < 0)
res = x;
yield res;
}
};
}
export function maxByScan(cf) {
return async function* (xs) {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done)
yield null;
let res = value;
for await (const x of it) {
if (cf(x, res) > 0)
res = x;
yield res;
}
};
}
export function sum(zero = 0) {
return async function (xs) {
let res = zero;
for await (const x of xs)
res += x;
return res;
};
}
export function replaceWhen(pf, ys) {
return async function* (xs) {
for await (const [x, y] of zip2(xs, ys)) {
if (!pf(x))
yield x;
else
yield y;
}
};
}
export function grouped(n, step = n) {
return async function* (xs) {
let group = [];
for await (const x of xs) {
group.push(x);
if (group.length === n) {
yield [...group];
for (let i = 0; i < step; i++)
group.shift();
}
}
};
}
export function startWith(...as) {
return async function* (xs) {
for await (const a of as)
yield a;
for await (const x of xs)
yield x;
};
}
export function endWith(...zs) {
return async function* (xs) {
for await (const x of xs)
yield x;
for await (const z of zs)
yield z;
};
}
export function sort(cf) {
return async function* (xs) {
let arr = [];
for await (const x of xs)
arr.push(x);
for (const x of arr.sort(cf))
yield x;
};
}
export function sortScan(cf) {
return async function* (xs) {
let arr = [];
for await (const x of xs) {
arr.push(x);
yield [...arr.sort(cf)];
}
};
}
export function flatMap(f) {
return async function* (xss) {
for await (const xs of xss)
for await (const x of xs)
yield await f(x);
};
}
export function distinctUntilChanged(comp = (a, b) => a === b) {
return async function* (xs) {
const it = forAwaitableIterator(xs);
let { done, value: initial } = await it.next();
if (done)
return;
yield initial;
for await (const x of it)
if (!comp(x, initial))
yield (initial = x);
};
}
export function unique(comp = (a, b) => a === b) {
return async function* (xs) {
const arr = [];
for await (const x of xs)
arr.push(x);
const unq = arr.filter((x, i, self) => self.findIndex(y => comp(x, y)) === i);
for (const u of unq)
yield u;
};
}
export function uniqueSorted(comp = (a, b) => a === b) {
return async function* (xs) {
const arr = [];
for await (const x of xs)
arr.push(x);
arr.sort();
for await (const x of distinctUntilChanged(comp)(arr))
yield x;
};
}
// CONSTRUCTORS
export async function* range(start = 0, end = Number.MAX_SAFE_INTEGER, step = 1) {
for (let i = start; end > start ? i < end : i > end; i += step)
yield i;
}
// TODO: rename to `entries`?
export async function* enumerate(xs) {
let i = 0;
for await (const x of xs)
yield [i++, x];
}
export async function* concat(...xss) {
for (const xs of xss)
for await (const x of xs)
yield x;
}
export const chain = concat;
export async function* zip2(xs, ys) {
const xit = forAwaitableIterator(xs);
const yit = forAwaitableIterator(ys);
while (true) {
const [xr, yr] = await Promise.all([xit.next(), yit.next()]);
if (xr.done || yr.done)
break;
yield [xr.value, yr.value];
}
}
export async function* zip3(xs, ys, zs) {
const xit = forAwaitableIterator(xs);
const yit = forAwaitableIterator(ys);
const zit = forAwaitableIterator(zs);
while (true) {
const [xr, yr, zr] = await Promise.all([xit.next(), yit.next(), zit.next()]);
if (xr.done || yr.done || zr.done)
break;
yield [xr.value, yr.value, zr.value];
}
}
export async function* zip(...xss) {
const its = xss.map(forAwaitableIterator);
while (true) {
const rs = await Promise.all(its.map(it => it.next()));
if (rs.some(r => r.done))
break;
yield rs.map(r => r.value);
}
}
// TODO: rename? Is this how regular zip commonly works?
export async function* zipOuter(...xss) {
const its = xss.map(forAwaitableIterator);
while (true) {
const rs = await Promise.all(its.map(it => it.next()));
if (rs.every(r => r.done))
break;
yield rs.map(r => r.value);
}
}
export async function* product2(as, bs) {
// if (as === bs) [as, bs] = asyncTee(as);
let bs2;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of bs2) {
yield [a, b];
}
}
}
export async function* product3(as, bs, cs) {
// if (as === bs) [as, bs] = asyncTee(as);
// if (as === cs) [as, cs] = asyncTee(as);
// if (bs === cs) [bs, cs] = asyncTee(bs);
let bs2;
let cs2;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of bs2) {
[cs, cs2] = asyncTee(cs);
for await (const c of cs2) {
yield [a, b, c];
}
}
}
}
// TODO: generalize to n parameters
export async function* product(xs, ...xss) {
throw new Error('Not implemented');
}
// TODO: other name (look at python itertools?)
// TODO: fix implementation
export async function* combinations2(xs) {
let [as, bs] = asyncTee(xs);
let bs2;
let i = 1;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of skip(i++)(bs2)) {
yield [a, b];
}
}
}
export async function* combinations3(xs) {
throw Error('Not implemented');
// let [as, bs, cs] = asyncTeeN(xs, 3);
// let bs2: ForOfAwaitable<X>;
// let cs2: ForOfAwaitable<X>;
// let i = 1;
// let j = 2;
// for await (const a of as) {
// [bs, bs2] = asyncTee(bs);
// for await (const b of skip<X>(i++)(bs2)) {
// [cs, cs2] = asyncTee(cs);
// for await (const c of skip<X>(j++)(cs2)) {
// yield [a, b, c];
// }
// }
// }
}
export async function* combinations(xs, r = 2) {
throw Error('Not implemented');
}
export async function* combinationsWithReplacement2(xs) {
let [as, bs] = asyncTee(xs);
let bs2;
let i = 0;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of skip(i++)(bs2)) {
yield [a, b];
}
}
}
export async function* combinationsWithReplacement3(xs) {
throw Error('Not implemented');
// let [as, bs, cs] = asyncTeeN(xs, 3);
// let bs2: ForOfAwaitable<X>;
// let cs2: ForOfAwaitable<X>;
// let i = 0;
// let j = 0;
// for await (const a of as) {
// [bs, bs2] = asyncTee(bs);
// for await (const b of skip<X>(i++)(bs2)) {
// [cs, cs2] = asyncTee(cs);
// for await (const c of skip<X>(j++)(cs2)) {
// yield [a, b, c];
// }
// }
// }
}
export async function* combinationsWithReplacement(xs, r = 2) {
throw Error('Not implemented');
}
export async function* permutations2(xs) {
throw Error('Not implemented');
}
export async function* permutations3(xs) {
throw Error('Not implemented');
}
export async function* permutations(xs, r = 2) {
throw Error('Not implemented');
}
export async function* constantly(value) {
while (true)
yield value;
}
export async function* cycle(xs) {
let xs2;
while (true) {
[xs, xs2] = asyncTee(xs);
for await (const x of xs2)
yield x;
}
}
export async function* repeat(xs, n) {
let xs2;
for (let i = 0; i < n; i++) {
[xs, xs2] = asyncTee(xs);
for await (const x of xs2)
yield x;
}
}
export async function* interleave2(xs, ys) {
const itx = forAwaitableIterator(xs);
const ity = forAwaitableIterator(ys);
while (true) {
const rx = await itx.next();
if (rx.done)
break;
else
yield rx.value;
const ry = await ity.next();
if (ry.done)
break;
else
yield ry.value;
}
}
export async function* interleave3(xs, ys, zs) {
const itx = forAwaitableIterator(xs);
const ity = forAwaitableIterator(ys);
const itz = forAwaitableIterator(zs);
while (true) {
const rx = await itx.next();
if (rx.done)
break;
else
yield rx.value;
const ry = await ity.next();
if (ry.done)
break;
else
yield ry.value;
const rz = await itz.next();
if (rz.done)
break;
else
yield rz.value;
}
}
export async function* interleave(...xss) {
const its = xss.map(forAwaitableIterator);
// Throwback to the 90s
outerloop: while (true) {
for (const it of its) {
const { done, value } = await it.next();
// Yup, this just happened
if (done)
break outerloop;
else
yield value;
}
}
}
export async function pipe(x, ...fs) {
let res = await x;
for (const f of fs)
res = await f(res);
return res;
}
//# sourceMappingURL=async-iter.js.map