UNPKG

gf-combination-js

Version:

Combination functions for Array and Generator

165 lines (132 loc) 3.98 kB
const GF = require('gf-js'); /** * Math product * * @param {Array<GeneratorFunction|Array>} iterables Array of (Array | GeneratorFunction) * @param {Number} repeat number of time repeat */ GF.iproduct = function* iproduct(iterables, repeat = 1) { function *__dot(accumulator, iterable) { for (let arr of accumulator) { yield* iterable.map(v => [...arr, v]); } } //convert each iterable to array let arrays = iterables.map(iterable => Array.isArray(iterable) ? iterable : [...iterable]); //repeat arrays let pools = []; while (repeat--) { pools = [...pools, ...arrays]; } let accumulator = [[]]; for (let iterable of pools) { accumulator = __dot(accumulator, iterable) } yield* accumulator; } /** * * @param {*} iterables * @param {*} repeat */ GF.product = (iterables, repeat = 1) => [...GF.iproduct(iterables, repeat)]; /** * * @param {Array} iterable * @param {Number} r */ GF.ipermutations = function* (iterable, r = undefined) { let pool = Array.isArray(iterable) ? iterable : [...iterable]; let n = pool.length; r = r || n; if (r > n) return; let indices = GF.range(n); let cycles = GF.range(n, n - r, -1); yield indices.slice(0, r).map(i => pool[i]); while (n) { let i; for (i = r - 1; i >= 0; i--) { cycles[i] -= 1; if (cycles[i] == 0) { indices = [...indices.slice(0, i), ...indices.slice(i + 1), indices[i]]; cycles[i] = n - i; } else { let j = cycles[i]; [indices[i], indices[indices.length - j]] = [indices[indices.length - j], indices[i]]; yield indices.slice(0, r).map(i => pool[i]); break; } } if (i < 0) break; } } /** * Permutations * * @param {*} iterable * @param {*} r */ GF.permutations = (iterable, r) => [...GF.ipermutations(iterable, r)] /** * * @param {*} r */ GF.prototype.ipermutations = function (r) { return GF.ipermutations(this, r); } /** * * @param {*} r */ GF.prototype.permutations = function (r) { returnGF.permutations(this, r); } /** * * @param {*} iterable * @param {*} r */ GF.icombinations = function* (iterable, r = undefined) { let pool = Array.isArray(iterable) ? iterable : [...iterable]; let n = pool.length; r = r || n; if (r > n) return; let indices = Array.range(r) yield indices.map(i => pool[i]); while (true) { let i; for (i = r - 1; i >= 0; i--) { if (indices[i] != i + n - r) break; } if (i < 0) break; indices[i] += 1; for (let j = i + 1; j < r; j++) { indices[j] = indices[j - 1] + 1; } yield indices.map(i => pool[i]); } } /** * * @param {*} iterable * @param {*} r */ GF.combinations = function (iterable, r) { return [...GF.icombinations(iterable, r)]; } /** * * @param {*} r */ GF.prototype.icombinations = function (r) { return GF.icombinations(this, r); } /** * * @param {*} r */ GF.prototype.combinations = function (r) { return GF.combinations(this, r); } Array.iproduct = GF.iproduct; Array.product = GF.product; Array.ipermutations = GF.ipermutations; Array.permutations = GF.permutations; Array.prototype.ipermutations = function (r) { return GF.ipermutations(this, r); } Array.prototype.permutations = function (r) { return GF.permutations(this, r); } Array.icombinations = GF.icombinations; Array.combinations = GF.combinations; Array.prototype.icombinations = function (r) { return GF.icombinations(this, r); } Array.prototype.combinations = function (r) { return GF.combinations(this, r); } module.exports = GF;