itertools
Version:
A JavaScript port of Python's awesome itertools standard library
634 lines (630 loc) • 14.1 kB
JavaScript
// src/utils.ts
function keyToCmp(keyFn) {
return (a, b) => {
const ka = keyFn(a);
const kb = keyFn(b);
if (typeof ka === "boolean" && typeof kb === "boolean") {
return ka === kb ? 0 : !ka && kb ? -1 : 1;
} else if (typeof ka === "number" && typeof kb === "number") {
return ka - kb;
} else if (typeof ka === "string" && typeof kb === "string") {
return ka === kb ? 0 : ka < kb ? -1 : 1;
} else {
return -1;
}
};
}
function identityPredicate(x) {
return !!x;
}
function numberIdentity(x) {
if (typeof x !== "number") {
throw new Error("Inputs must be numbers");
}
return x;
}
function primitiveIdentity(x) {
if (typeof x !== "string" && typeof x !== "number" && typeof x !== "boolean") {
throw new Error("Please provide a key function that can establish object identity");
}
return x;
}
// src/more-itertools.ts
function* chunked(iterable, size) {
if (size < 1) {
throw new Error(`Invalid chunk size: ${size}`);
}
const it = iter(iterable);
for (; ; ) {
const chunk = take(size, it);
if (chunk.length > 0) {
yield chunk;
}
if (chunk.length < size) {
return;
}
}
}
function* flatten(iterableOfIterables) {
for (const iterable of iterableOfIterables) {
for (const item of iterable) {
yield item;
}
}
}
function intersperse(value, iterable) {
const stream = flatten(izip(repeat(value), iterable));
stream.next();
return stream;
}
function* itake(n, iterable) {
const it = iter(iterable);
let count2 = n;
while (count2-- > 0) {
const s = it.next();
if (!s.done) {
yield s.value;
} else {
return;
}
}
}
function* pairwise(iterable) {
const it = iter(iterable);
const first2 = it.next();
if (first2.done) {
return;
}
let r1 = first2.value;
for (const r2 of it) {
yield [r1, r2];
r1 = r2;
}
}
function partition(iterable, predicate) {
const good = [];
const bad = [];
let index = 0;
for (const item of iterable) {
if (predicate(item, index++)) {
good.push(item);
} else {
bad.push(item);
}
}
return [good, bad];
}
function* roundrobin(...iters) {
const iterables = map(iters, iter);
while (iterables.length > 0) {
let index = 0;
while (index < iterables.length) {
const it = iterables[index];
const result = it.next();
if (!result.done) {
yield result.value;
index++;
} else {
iterables.splice(index, 1);
}
}
}
}
function* heads(...iters) {
const iterables = map(iters, iter);
while (iterables.length > 0) {
let index = 0;
const round = [];
while (index < iterables.length) {
const it = iterables[index];
const result = it.next();
if (!result.done) {
round.push(result.value);
index++;
} else {
iterables.splice(index, 1);
}
}
if (round.length > 0) {
yield round;
}
}
}
function take(n, iterable) {
return Array.from(itake(n, iterable));
}
function* uniqueEverseen(iterable, keyFn = primitiveIdentity) {
const seen = /* @__PURE__ */ new Set();
for (const item of iterable) {
const key = keyFn(item);
if (!seen.has(key)) {
seen.add(key);
yield item;
}
}
}
function dupes(iterable, keyFn = primitiveIdentity) {
const multiples = /* @__PURE__ */ new Map();
{
const singles = /* @__PURE__ */ new Map();
for (const item of iterable) {
const key = keyFn(item);
if (multiples.has(key)) {
multiples.get(key).push(item);
} else if (singles.has(key)) {
multiples.set(key, [singles.get(key), item]);
singles.delete(key);
} else {
singles.set(key, item);
}
}
}
return multiples.values();
}
function* uniqueJustseen(iterable, keyFn = primitiveIdentity) {
let last = void 0;
for (const item of iterable) {
const key = keyFn(item);
if (key !== last) {
yield item;
last = key;
}
}
}
// src/itertools.ts
var SENTINEL = Symbol();
function chain(...iterables) {
return flatten(iterables);
}
function* count(start = 0, step = 1) {
let n = start;
for (; ; ) {
yield n;
n += step;
}
}
function compress(data, selectors) {
return Array.from(icompress(data, selectors));
}
function* cycle(iterable) {
const saved = [];
for (const element of iterable) {
yield element;
saved.push(element);
}
while (saved.length > 0) {
for (const element of saved) {
yield element;
}
}
}
function* dropwhile(iterable, predicate) {
let index = 0;
const it = iter(iterable);
let res;
while (!(res = it.next()).done) {
const value = res.value;
if (!predicate(value, index++)) {
yield value;
break;
}
}
for (const value of it) {
yield value;
}
}
function* groupby(iterable, keyFn = primitiveIdentity) {
const it = iter(iterable);
let currentValue;
let currentKey = SENTINEL;
let targetKey = currentKey;
const grouper = function* grouper2(tgtKey) {
while (currentKey === tgtKey) {
yield currentValue;
const nextVal = it.next();
if (nextVal.done) return;
currentValue = nextVal.value;
currentKey = keyFn(currentValue);
}
};
for (; ; ) {
while (currentKey === targetKey) {
const nextVal = it.next();
if (nextVal.done) {
currentKey = SENTINEL;
return;
}
currentValue = nextVal.value;
currentKey = keyFn(currentValue);
}
targetKey = currentKey;
yield [currentKey, grouper(targetKey)];
}
}
function* icompress(data, selectors) {
for (const [d, s] of izip(data, selectors)) {
if (s) {
yield d;
}
}
}
function* ifilter(iterable, predicate) {
let index = 0;
for (const value of iterable) {
if (predicate(value, index++)) {
yield value;
}
}
}
function* imap(iterable, mapper) {
for (const value of iterable) {
yield mapper(value);
}
}
function* islice(iterable, stopOrStart, possiblyStop, step = 1) {
let start, stop;
if (possiblyStop !== void 0) {
start = stopOrStart;
stop = possiblyStop;
} else {
start = 0;
stop = stopOrStart;
}
if (start < 0) throw new Error("start cannot be negative");
if (stop !== null && stop < 0) throw new Error("stop cannot be negative");
if (step <= 0) throw new Error("step cannot be negative");
let i = -1;
const it = iter(iterable);
let res;
while (true) {
i++;
if (stop !== null && i >= stop) return;
res = it.next();
if (res.done) return;
if (i < start) continue;
if ((i - start) % step === 0) {
yield res.value;
}
}
}
function* izip(xs, ys) {
const ixs = iter(xs);
const iys = iter(ys);
for (; ; ) {
const x = ixs.next();
const y = iys.next();
if (!x.done && !y.done) {
yield [x.value, y.value];
} else {
return;
}
}
}
function* izip3(xs, ys, zs) {
const ixs = iter(xs);
const iys = iter(ys);
const izs = iter(zs);
for (; ; ) {
const x = ixs.next();
const y = iys.next();
const z = izs.next();
if (!x.done && !y.done && !z.done) {
yield [x.value, y.value, z.value];
} else {
return;
}
}
}
var izip2 = izip;
function* izipLongest2(xs, ys, filler) {
const filler_ = filler;
const ixs = iter(xs);
const iys = iter(ys);
for (; ; ) {
const x = ixs.next();
const y = iys.next();
if (x.done && y.done) {
return;
} else {
yield [!x.done ? x.value : filler_, !y.done ? y.value : filler_];
}
}
}
function* izipLongest3(xs, ys, zs, filler) {
const filler_ = filler;
const ixs = iter(xs);
const iys = iter(ys);
const izs = iter(zs);
for (; ; ) {
const x = ixs.next();
const y = iys.next();
const z = izs.next();
if (x.done && y.done && z.done) {
return;
} else {
yield [!x.done ? x.value : filler_, !y.done ? y.value : filler_, !z.done ? z.value : filler_];
}
}
}
function* izipMany(...iters) {
const iterables = iters.map(iter);
for (; ; ) {
const heads2 = iterables.map((xs) => xs.next());
if (every(heads2, (h) => !h.done)) {
yield heads2.map((h) => h.value);
} else {
return;
}
}
}
function* permutations(iterable, r) {
const pool = Array.from(iterable);
const n = pool.length;
const x = r ?? n;
if (x > n) {
return;
}
let indices = Array.from(range(n));
const cycles = Array.from(range(n, n - x, -1));
const poolgetter = (i) => pool[i];
yield indices.slice(0, x).map(poolgetter);
while (n > 0) {
let cleanExit = true;
for (const i of range(x - 1, -1, -1)) {
cycles[i] -= 1;
if (cycles[i] === 0) {
indices = indices.slice(0, i).concat(indices.slice(i + 1)).concat(indices.slice(i, i + 1));
cycles[i] = n - i;
} else {
const j = cycles[i];
const [p, q] = [indices[indices.length - j], indices[i]];
indices[i] = p;
indices[indices.length - j] = q;
yield indices.slice(0, x).map(poolgetter);
cleanExit = false;
break;
}
}
if (cleanExit) {
return;
}
}
}
function* repeat(thing, times) {
if (times === void 0) {
for (; ; ) {
yield thing;
}
} else {
for (const _ of range(times)) {
yield thing;
}
}
}
function* takewhile(iterable, predicate) {
let index = 0;
const it = iter(iterable);
let res;
while (!(res = it.next()).done) {
const value = res.value;
if (!predicate(value, index++)) return;
yield value;
}
}
function zipLongest2(xs, ys, filler) {
return Array.from(izipLongest2(xs, ys, filler));
}
function zipLongest3(xs, ys, zs, filler) {
return Array.from(izipLongest3(xs, ys, zs, filler));
}
var izipLongest = izipLongest2;
var zipLongest = zipLongest2;
function zipMany(...iters) {
return Array.from(izipMany(...iters));
}
// src/builtins.ts
function find(iterable, predicate) {
const it = iter(iterable);
if (predicate === void 0) {
const value = it.next();
return value.done ? void 0 : value.value;
} else {
let res;
let i = 0;
while (!(res = it.next()).done) {
const value = res.value;
if (predicate(value, i++)) {
return value;
}
}
return void 0;
}
}
function every(iterable, predicate = identityPredicate) {
let index = 0;
for (const item of iterable) {
if (!predicate(item, index++)) {
return false;
}
}
return true;
}
function some(iterable, predicate = identityPredicate) {
let index = 0;
for (const item of iterable) {
if (predicate(item, index++)) {
return true;
}
}
return false;
}
var all = every;
var any = some;
function contains(haystack, needle) {
return some(haystack, (x) => x === needle);
}
function* enumerate(iterable, start = 0) {
let index = start;
for (const value of iterable) {
yield [index++, value];
}
}
function filter(iterable, predicate) {
return Array.from(ifilter(iterable, predicate));
}
function iter(iterable) {
return iterable[Symbol.iterator]();
}
function map(iterable, mapper) {
return Array.from(imap(iterable, mapper));
}
function max(iterable, keyFn = numberIdentity) {
return reduce2(iterable, (x, y) => keyFn(x) > keyFn(y) ? x : y);
}
function min(iterable, keyFn = numberIdentity) {
return reduce2(iterable, (x, y) => keyFn(x) < keyFn(y) ? x : y);
}
function range_(start, stop, step) {
const counter = count(start, step);
const pred = step >= 0 ? (n) => n < stop : (n) => n > stop;
return takewhile(counter, pred);
}
function range(startOrStop, definitelyStop, step = 1) {
if (definitelyStop !== void 0) {
return range_(startOrStop, definitelyStop, step);
} else {
return range_(0, startOrStop, step);
}
}
function reduce(iterable, reducer, start) {
if (start === void 0) {
return reduce2(iterable, reducer);
} else {
return reduce3(iterable, reducer, start);
}
}
function reduce3(iterable, reducer, start) {
let output = start;
let index = 0;
for (const item of iterable) {
output = reducer(output, item, index++);
}
return output;
}
function reduce2(iterable, reducer) {
const it = iter(iterable);
const start = find(it);
if (start === void 0) {
return void 0;
} else {
return reduce3(it, reducer, start);
}
}
function sorted(iterable, keyFn = primitiveIdentity, reverse = false) {
const result = Array.from(iterable);
result.sort(keyToCmp(keyFn));
if (reverse) {
result.reverse();
}
return result;
}
function sum(iterable) {
return reduce(iterable, (x, y) => x + y, 0);
}
function zip(xs, ys) {
return Array.from(izip(xs, ys));
}
function zip3(xs, ys, zs) {
return Array.from(izip3(xs, ys, zs));
}
// src/custom.ts
function isNullish(x) {
return x != null;
}
function isDefined(x) {
return x !== void 0;
}
function icompact(iterable) {
return ifilter(iterable, isNullish);
}
function compact(iterable) {
return Array.from(icompact(iterable));
}
function compactObject(obj) {
const result = {};
for (const [key, value_] of Object.entries(obj)) {
const value = value_;
if (value != null) {
result[key] = value;
}
}
return result;
}
function first(iterable, keyFn) {
return find(iterable, keyFn ?? isDefined);
}
function flatmap(iterable, mapper) {
return flatten(imap(iterable, mapper));
}
export {
all,
any,
chain,
chunked,
compact,
compactObject,
compress,
contains,
count,
cycle,
dropwhile,
dupes,
enumerate,
every,
filter,
find,
first,
flatmap,
flatten,
groupby,
heads,
icompact,
icompress,
ifilter,
imap,
intersperse,
islice,
itake,
iter,
izip,
izip2,
izip3,
izipLongest,
izipLongest3,
izipMany,
map,
max,
min,
pairwise,
partition,
permutations,
range,
reduce,
repeat,
roundrobin,
some,
sorted,
sum,
take,
takewhile,
uniqueEverseen,
uniqueJustseen,
zip,
zip3,
zipLongest,
zipLongest3,
zipMany
};
// istanbul ignore else -- @preserve
// istanbul ignore if -- @preserve
//# sourceMappingURL=index.js.map