locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
281 lines (280 loc) • 9.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toIterableArray = toIterableArray;
exports.parseZipLongestArgs = parseZipLongestArgs;
exports.parseProductArgs = parseProductArgs;
exports.itertoolsAccumulate = itertoolsAccumulate;
exports.itertoolsBatched = itertoolsBatched;
exports.itertoolsChain = itertoolsChain;
exports.itertoolsCompress = itertoolsCompress;
exports.itertoolsIslice = itertoolsIslice;
exports.itertoolsPairwise = itertoolsPairwise;
exports.itertoolsZipLongest = itertoolsZipLongest;
exports.itertoolsCombinations = itertoolsCombinations;
exports.itertoolsCombinationsWithReplacement = itertoolsCombinationsWithReplacement;
exports.itertoolsPermutations = itertoolsPermutations;
exports.itertoolsProduct = itertoolsProduct;
const _operator_ts_1 = require("./_operator.js");
function toIterableArray(iterable, functionName) {
if (Array.isArray(iterable)) {
return [...iterable];
}
if (typeof iterable === 'string') {
return [...iterable];
}
if (isIterable(iterable)) {
return Array.from(iterable);
}
throw new TypeError(`${functionName}() expected an iterable`);
}
function parseZipLongestArgs(args) {
if (args.length === 0) {
return { iterables: [], fillvalue: null };
}
const options = extractIterableOptions(args[args.length - 1]);
if (!options) {
return { iterables: args, fillvalue: null };
}
return {
iterables: args.slice(0, -1),
fillvalue: options.fillvalue ?? null,
};
}
function parseProductArgs(args) {
if (args.length === 0) {
return { iterables: [], repeat: 1 };
}
const options = extractRepeatOptions(args[args.length - 1]);
if (!options) {
return { iterables: args, repeat: 1 };
}
return {
iterables: args.slice(0, -1),
repeat: toNonNegativeInteger(options.repeat ?? 1, 'product'),
};
}
function itertoolsAccumulate(iterable, func) {
const values = toIterableArray(iterable, 'accumulate');
if (values.length === 0) {
return [];
}
const callback = func ?? defaultAccumulateStep;
const result = [values[0]];
for (let index = 1; index < values.length; index += 1) {
result.push(callback(result[result.length - 1], values[index]));
}
return result;
}
function itertoolsBatched(iterable, n) {
const values = toIterableArray(iterable, 'batched');
const batchSize = toPositiveInteger(n, 'batched', 'n must be at least one');
const result = [];
for (let index = 0; index < values.length; index += batchSize) {
result.push(values.slice(index, index + batchSize));
}
return result;
}
function itertoolsChain(iterables) {
return iterables.flatMap((iterable) => toIterableArray(iterable, 'chain'));
}
function itertoolsCompress(data, selectors) {
const values = toIterableArray(data, 'compress');
const masks = toIterableArray(selectors, 'compress');
const result = [];
for (let index = 0; index < values.length && index < masks.length; index += 1) {
if ((0, _operator_ts_1.pythonTruth)(masks[index])) {
result.push(values[index]);
}
}
return result;
}
function itertoolsIslice(iterable, args) {
const values = toIterableArray(iterable, 'islice');
const { start, stop, step } = parseSliceArgs(args);
const result = [];
for (let index = start; index < stop && index < values.length; index += step) {
result.push(values[index]);
}
return result;
}
function itertoolsPairwise(iterable) {
const values = toIterableArray(iterable, 'pairwise');
const result = [];
for (let index = 0; index + 1 < values.length; index += 1) {
result.push([values[index], values[index + 1]]);
}
return result;
}
function itertoolsZipLongest(args) {
const { iterables, fillvalue } = parseZipLongestArgs(args);
const pools = iterables.map((iterable) => toIterableArray(iterable, 'zip_longest'));
const width = pools.reduce((max, pool) => Math.max(max, pool.length), 0);
const result = [];
for (let row = 0; row < width; row += 1) {
result.push(pools.map((pool) => (row < pool.length ? pool[row] : fillvalue)));
}
return result;
}
function itertoolsCombinations(iterable, r) {
const pool = toIterableArray(iterable, 'combinations');
const size = toNonNegativeInteger(r, 'combinations');
const result = [];
buildCombinations(pool, size, 0, [], result);
return result;
}
function itertoolsCombinationsWithReplacement(iterable, r) {
const pool = toIterableArray(iterable, 'combinations_with_replacement');
const size = toNonNegativeInteger(r, 'combinations_with_replacement');
const result = [];
if (size === 0) {
return [[]];
}
if (pool.length === 0) {
return [];
}
buildCombinationsWithReplacement(pool, size, 0, [], result);
return result;
}
function itertoolsPermutations(iterable, r) {
const pool = toIterableArray(iterable, 'permutations');
const size = r === undefined ? pool.length : toNonNegativeInteger(r, 'permutations');
const result = [];
if (size > pool.length) {
return [];
}
buildPermutations(pool, size, [], new Set(), result);
return result;
}
function itertoolsProduct(args) {
const { iterables, repeat } = parseProductArgs(args);
const basePools = iterables.map((iterable) => toIterableArray(iterable, 'product'));
const pools = repeat === 1
? basePools
: Array.from({ length: repeat }, () => basePools).flatMap((poolSet) => poolSet.map((pool) => [...pool]));
if (pools.length === 0) {
return [[]];
}
if (pools.some((pool) => pool.length === 0)) {
return [];
}
const result = [];
buildProduct(pools, 0, [], result);
return result;
}
function defaultAccumulateStep(left, right) {
return (0, _operator_ts_1.pythonAdd)(left, right, 'accumulate');
}
function parseSliceArgs(args) {
if (args.length === 0) {
throw new TypeError("islice() missing required argument 'stop'");
}
if (args.length > 3) {
throw new TypeError(`islice expected at most 4 arguments, got ${args.length + 1}`);
}
let start = 0;
let stop = 0;
let step = 1;
if (args.length === 1) {
stop = toNonNegativeInteger(args[0], 'islice');
}
else {
start = toNonNegativeInteger(args[0], 'islice');
stop = toNonNegativeInteger(args[1], 'islice');
if (args.length === 3) {
step = toPositiveInteger(args[2], 'islice', 'step for islice() must be a positive integer or None');
}
}
return { start, stop, step };
}
function buildCombinations(pool, size, start, current, result) {
if (current.length === size) {
result.push([...current]);
return;
}
for (let index = start; index <= pool.length - (size - current.length); index += 1) {
current.push(pool[index]);
buildCombinations(pool, size, index + 1, current, result);
current.pop();
}
}
function buildCombinationsWithReplacement(pool, size, start, current, result) {
if (current.length === size) {
result.push([...current]);
return;
}
for (let index = start; index < pool.length; index += 1) {
current.push(pool[index]);
buildCombinationsWithReplacement(pool, size, index, current, result);
current.pop();
}
}
function buildPermutations(pool, size, current, usedIndexes, result) {
if (current.length === size) {
result.push([...current]);
return;
}
for (let index = 0; index < pool.length; index += 1) {
if (usedIndexes.has(index)) {
continue;
}
usedIndexes.add(index);
current.push(pool[index]);
buildPermutations(pool, size, current, usedIndexes, result);
current.pop();
usedIndexes.delete(index);
}
}
function buildProduct(pools, index, current, result) {
if (index >= pools.length) {
result.push([...current]);
return;
}
const pool = pools[index] ?? [];
for (const value of pool) {
current.push(value);
buildProduct(pools, index + 1, current, result);
current.pop();
}
}
function toPositiveInteger(value, functionName, message) {
const integer = toNonNegativeInteger(value, functionName);
if (integer < 1) {
throw new Error(message ?? `${functionName}() expected a positive integer`);
}
return integer;
}
function toNonNegativeInteger(value, functionName) {
if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
throw new TypeError(`${functionName}() expected a non-negative integer`);
}
return value;
}
function isIterable(value) {
return ((typeof value === 'object' || typeof value === 'function') &&
value !== null &&
Symbol.iterator in value &&
typeof value[Symbol.iterator] === 'function');
}
function extractIterableOptions(value) {
if (!isPlainObject(value)) {
return null;
}
const keys = Object.keys(value);
if (keys.length === 0 || keys.some((key) => key !== 'fillvalue')) {
return null;
}
return value;
}
function extractRepeatOptions(value) {
if (!isPlainObject(value)) {
return null;
}
const keys = Object.keys(value);
if (keys.length === 0 || keys.some((key) => key !== 'repeat')) {
return null;
}
return value;
}
function isPlainObject(value) {
return typeof value === 'object' && value !== null && Object.getPrototypeOf(value) === Object.prototype;
}