commit 1aa682fd34b956df55c525af92c0454fa104cb16 Author: upstream Date: Thu Sep 3 14:04:54 2026 +0200 Upstream simple-statistics/simple-statistics state of the touched files before e26d2c41ca diff --git a/src/combinations_replacement.js b/src/combinations_replacement.js new file mode 100644 index 0000000..1fc5832 --- /dev/null +++ b/src/combinations_replacement.js @@ -0,0 +1,43 @@ +/** + * Implementation of [Combinations](https://en.wikipedia.org/wiki/Combination) with replacement + * Combinations are unique subsets of a collection - in this case, k x from a collection at a time. + * 'With replacement' means that a given element can be chosen multiple times. + * Unlike permutation, order doesn't matter for combinations. + * + * @param {Array} x any type of data + * @param {int} k the number of objects in each group (without replacement) + * @returns {Array} array of permutations + * @example + * combinationsReplacement([1, 2], 2); // => [[1, 1], [1, 2], [2, 2]] + */ +function combinationsReplacement(x, k) { + const combinationList = []; + + for (let i = 0; i < x.length; i++) { + if (k === 1) { + // If we're requested to find only one element, we don't need + // to recurse: just push `x[i]` onto the list of combinations. + combinationList.push([x[i]]); + } else { + // Otherwise, recursively find combinations, given `k - 1`. Note that + // we request `k - 1`, so if you were looking for k=3 combinations, we're + // requesting k=2. This -1 gets reversed in the for loop right after this + // code, since we concatenate `x[i]` onto the selected combinations, + // bringing `k` back up to your requested level. + // This recursion may go many levels deep, since it only stops once + // k=1. + const subsetCombinations = combinationsReplacement( + x.slice(i, x.length), + k - 1 + ); + + for (let j = 0; j < subsetCombinations.length; j++) { + combinationList.push([x[i]].concat(subsetCombinations[j])); + } + } + } + + return combinationList; +} + +export default combinationsReplacement; diff --git a/test/combinations_replacement.test.js b/test/combinations_replacement.test.js new file mode 100644 index 0000000..4265341 --- /dev/null +++ b/test/combinations_replacement.test.js @@ -0,0 +1,18 @@ +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; +import * as ss from "../index.js"; + +describe("combinations", function () { + it("generates 1 permutation", function () { + assert.deepEqual(ss.combinationsReplacement(Object.freeze([1]), 1), [ + [1] + ]); + }); + it("generates combinations of 1,2 choosing two at a time, with replacement", function () { + assert.deepEqual(ss.combinationsReplacement(Object.freeze([1, 2]), 2), [ + [1, 1], + [1, 2], + [2, 2] + ]); + }); +});