itertools-ts
Version:
Extended itertools port for TypeScript and JavaScript. Provides a huge set of functions for working with iterable collections (including async ones)
512 lines • 15.8 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
import { LengthError } from "./exceptions";
import { reduce, single, Stream } from "./index";
import { toAsyncIterator, toIterator } from "./transform";
export var MultipleIterationMode;
(function (MultipleIterationMode) {
MultipleIterationMode[MultipleIterationMode["SHORTEST"] = 0] = "SHORTEST";
MultipleIterationMode[MultipleIterationMode["LONGEST"] = 1] = "LONGEST";
MultipleIterationMode[MultipleIterationMode["STRICT_EQUAL"] = 2] = "STRICT_EQUAL";
})(MultipleIterationMode || (MultipleIterationMode = {}));
/**
* Creates iterable instance to iterate several iterables simultaneously.
*
* @param mode shortest, longest or strict equal
* @param iterables
* @param noValueFiller
* @param iterables
*/
export function* createMultipleIterator(mode, noValueFiller, ...iterables) {
if (iterables.length === 0) {
return;
}
const iterators = [];
for (const it of iterables) {
iterators.push(toIterator(it));
}
iterate: while (true) {
const statuses = single.map(iterators, (it) => it.next());
const values = [];
let allValid = true;
let anyValid = false;
for (const status of statuses) {
let value;
if (status.done) {
allValid = false;
value = noValueFiller;
}
else {
anyValid = true;
value = status.value;
}
values.push(value);
}
if (!allValid && anyValid) {
switch (mode) {
case MultipleIterationMode.SHORTEST:
break iterate;
case MultipleIterationMode.STRICT_EQUAL:
throw new LengthError("Iterators must have equal lengths");
}
}
if (!anyValid) {
break;
}
yield values;
}
}
/**
* Creates async iterable instance to iterate several iterables simultaneously.
*
* @param mode shortest, longest or strict equal
* @param iterables
* @param noValueFiller
* @param iterables
*/
export function createAsyncMultipleIterator(mode, noValueFiller, ...iterables) {
return __asyncGenerator(this, arguments, function* createAsyncMultipleIterator_1() {
if (iterables.length === 0) {
return yield __await(void 0);
}
const iterators = [];
for (const it of iterables) {
iterators.push(toAsyncIterator(it));
}
iterate: while (true) {
const statuses = [];
for (const it of iterators) {
const status = yield __await(it.next());
statuses.push(status);
}
const values = [];
let allValid = true;
let anyValid = false;
for (const status of statuses) {
let value;
if (status.done) {
allValid = false;
value = noValueFiller;
}
else {
anyValid = true;
value = status.value;
}
values.push(value);
}
if (!allValid && anyValid) {
switch (mode) {
case MultipleIterationMode.SHORTEST:
break iterate;
case MultipleIterationMode.STRICT_EQUAL:
throw new LengthError("Iterators must have equal lengths");
}
}
if (!anyValid) {
break;
}
yield yield __await(values);
}
});
}
/**
* Internal class for counting unique values usage.
*/
export class UsageMap {
constructor() {
this.addedMap = new Map();
this.deletedMap = new Map();
}
/**
* Adds new usage of value by given owner.
*
* @param value
* @param owner
*/
addUsage(value, owner) {
if (!this.addedMap.has(value)) {
this.addedMap.set(value, new Map());
}
const valueMap = this.addedMap.get(value);
if (!valueMap.has(owner)) {
valueMap.set(owner, 0);
}
valueMap.set(owner, valueMap.get(owner) + 1);
}
/**
* Removes usage of value.
*
* @param value
*/
deleteUsage(value) {
if (!this.deletedMap.has(value)) {
this.deletedMap.set(value, 1);
}
else {
this.deletedMap.set(value, this.deletedMap.get(value) + 1);
}
}
/**
* Returns owners count of given value.
*
* @param value
*/
getOwnersCount(value) {
var _a, _b;
const deletesCount = (_a = this.deletedMap.get(value)) !== null && _a !== void 0 ? _a : 0;
return Stream.of((_b = this.addedMap.get(value)) !== null && _b !== void 0 ? _b : new Map())
.map((datum) => datum[1])
.filter((count) => count > deletesCount)
.toValue((carry) => carry + 1, 0);
}
/**
* Returns usages count of given value.
*
* @param value
* @param maxOwnersCount
*/
getUsagesCount(value, maxOwnersCount = 1) {
var _a, _b;
const deletesCount = (_a = this.deletedMap.get(value)) !== null && _a !== void 0 ? _a : 0;
let owners = Stream.of((_b = this.addedMap.get(value)) !== null && _b !== void 0 ? _b : new Map())
.map((pair) => pair[1])
.map((value) => value - deletesCount)
.filter((value) => value > 0)
.toArray();
while (owners.length > maxOwnersCount) {
const minValue = reduce.toMin(owners);
owners = Stream.of(owners)
.map((value) => value - minValue)
.filter((value) => value > 0)
.toArray();
}
return reduce.toSum(owners);
}
}
/**
* No value filler monad.
*/
export class NoValueMonad {
}
/**
* Internal tool for duplicating another iterators using cache.
*/
export class TeeIterator {
/**
* TeeIterator constructor
*
* @param iterator
* @param relatedCount
*/
constructor(iterator, relatedCount) {
this.related = [];
this.positions = [];
this.cache = new Map();
this.lastCacheIndex = 0;
this.isValid = true;
this.iterator = iterator;
for (let i = 0; i < relatedCount; ++i) {
this.related.push(new RelatedIterable(this, i));
this.positions.push(0);
}
this.cacheNextValue();
}
/**
* Returns current value of related iterable.
*
* @param relatedIterable
*/
current(relatedIterable) {
const index = this.getPosition(relatedIterable);
return this.cache.get(index);
}
/**
* Moves related iterable to the next element.
*
* @param relatedIterable
*/
next(relatedIterable) {
const [relPos, minPos, maxPos] = [
this.getPosition(relatedIterable),
Math.min(...this.positions),
Math.max(...this.positions),
];
if (relPos === maxPos) {
this.cacheNextValue();
}
this.positions[relatedIterable.getId()]++;
if (minPos < Math.min(...this.positions)) {
this.cache.delete(minPos);
}
}
/**
* Returns true if related iterable is not done.
*
* @param relatedIterable
*/
valid(relatedIterable) {
return (this.getPosition(relatedIterable) < this.lastCacheIndex || this.isValid);
}
/**
* Returns related iterables list.
*/
getRelatedIterables() {
return this.related;
}
/**
* Gets and caches the next element of parent iterator.
*
* @private
*/
cacheNextValue() {
const status = this.iterator.next();
if (!status.done) {
this.cache.set(this.lastCacheIndex++, status.value);
}
this.isValid = !status.done;
}
/**
* Returns current position index of related iterable.
*
* @param related
*/
getPosition(related) {
return this.positions[related.getId()];
}
}
/**
* Duplicated iterable.
*/
export class RelatedIterable {
/**
* RelatedIterable constructor.
*
* @param parentIterable
* @param id
*/
constructor(parentIterable, id) {
this.parent = parentIterable;
this.id = id;
}
/**
* Id getter.
*/
getId() {
return this.id;
}
/**
* Returns true if the iterator is valid.
*/
valid() {
return this.parent.valid(this);
}
/**
* Moves the iterator to the next element.
*/
next() {
const result = { value: this.current(), done: !this.valid() };
if (!result.done) {
this.parent.next(this);
}
return result;
}
/**
* Returns current value of the iterator.
*/
current() {
return this.parent.valid(this) ? this.parent.current(this) : undefined;
}
/**
* Aggregated iterator.
*/
*[Symbol.iterator]() {
while (this.parent.valid(this)) {
yield this.parent.current(this);
this.parent.next(this);
}
}
}
/**
* Internal tool for duplicating another async iterators using cache.
*/
export class AsyncTeeIterator {
/**
* AsyncTeeIterator constructor
*
* @param iterator
* @param relatedCount
*/
constructor(iterator, relatedCount) {
this.related = [];
this.positions = [];
this.cache = new Map();
this.lastCacheIndex = 0;
this.isValid = true;
this.isFirstIteration = true;
this.iterator = iterator;
for (let i = 0; i < relatedCount; ++i) {
this.related.push(new AsyncRelatedIterable(this, i));
this.positions.push(0);
}
}
/**
* Returns current value of related iterable.
*
* @param relatedIterable
*/
current(relatedIterable) {
return __awaiter(this, void 0, void 0, function* () {
if (this.isFirstIteration) {
yield this.cacheNextValue();
}
const index = this.getPosition(relatedIterable);
return this.cache.get(index);
});
}
/**
* Moves related iterable to the next element.
*
* @param relatedIterable
*/
next(relatedIterable) {
return __awaiter(this, void 0, void 0, function* () {
const [relPos, minPos, maxPos] = [
this.getPosition(relatedIterable),
Math.min(...this.positions),
Math.max(...this.positions),
];
if (relPos === maxPos) {
yield this.cacheNextValue();
}
this.positions[relatedIterable.getId()]++;
if (minPos < Math.min(...this.positions)) {
this.cache.delete(minPos);
}
});
}
/**
* Returns true if related iterable is not done.
*
* @param relatedIterable
*/
valid(relatedIterable) {
return __awaiter(this, void 0, void 0, function* () {
if (this.isFirstIteration) {
yield this.cacheNextValue();
}
return (this.getPosition(relatedIterable) < this.lastCacheIndex || this.isValid);
});
}
/**
* Returns related iterables list.
*/
getRelatedIterables() {
return this.related;
}
/**
* Gets and caches the next element of parent iterator.
*
* @private
*/
cacheNextValue() {
return __awaiter(this, void 0, void 0, function* () {
const status = yield this.iterator.next();
if (!status.done) {
this.cache.set(this.lastCacheIndex++, status.value);
}
this.isFirstIteration = false;
this.isValid = !status.done;
});
}
/**
* Returns current position index of related iterable.
*
* @param related
*/
getPosition(related) {
return this.positions[related.getId()];
}
}
/**
* Duplicated async iterable.
*/
export class AsyncRelatedIterable {
/**
* AsyncRelatedIterable constructor.
*
* @param parentIterable
* @param id
*/
constructor(parentIterable, id) {
this.parent = parentIterable;
this.id = id;
}
/**
* Id getter.
*/
getId() {
return this.id;
}
/**
* Returns true if the iterator is valid.
*/
valid() {
return __awaiter(this, void 0, void 0, function* () {
return yield this.parent.valid(this);
});
}
/**
* Moves the iterator to the next element.
*/
next() {
return __awaiter(this, void 0, void 0, function* () {
const result = { value: yield this.current(), done: !(yield this.valid()) };
if (!result.done) {
yield this.parent.next(this);
}
return result;
});
}
/**
* Returns current value of the iterator.
*/
current() {
return __awaiter(this, void 0, void 0, function* () {
return (yield this.parent.valid(this))
? yield this.parent.current(this)
: undefined;
});
}
/**
* Aggregated iterator.
*/
[Symbol.asyncIterator]() {
return __asyncGenerator(this, arguments, function* _a() {
while (yield __await(this.parent.valid(this))) {
yield yield __await(yield __await(this.parent.current(this)));
yield __await(this.parent.next(this));
}
});
}
}
//# sourceMappingURL=tools.js.map