From db7ab9e299fb483e150809b89bc16f7ca52fcf7b Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Thu, 28 Jun 2018 21:28:50 +0300 Subject: [PATCH] Simplify permutateWithRepetitions algorithm. --- .../combinations/combineWithRepetitions.js | 6 +- .../combinations/combineWithoutRepetitions.js | 6 +- .../__test__/permutateWithRepetitions.test.js | 3 - .../permutateWithRepetitionsRecursive.test.js | 55 ------------------- .../permutations/permutateWithRepetitions.js | 52 +++++++----------- .../permutateWithRepetitionsRecursive.js | 37 ------------- 6 files changed, 24 insertions(+), 135 deletions(-) delete mode 100644 src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js delete mode 100644 src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js diff --git a/src/algorithms/sets/combinations/combineWithRepetitions.js b/src/algorithms/sets/combinations/combineWithRepetitions.js index a95d2857..8a743289 100644 --- a/src/algorithms/sets/combinations/combineWithRepetitions.js +++ b/src/algorithms/sets/combinations/combineWithRepetitions.js @@ -13,9 +13,7 @@ export default function combineWithRepetitions(comboOptions, comboLength) { // Eliminate characters one by one and concatenate them to // combinations of smaller lengths. - for (let optionIndex = 0; optionIndex < comboOptions.length; optionIndex += 1) { - const currentOption = comboOptions[optionIndex]; - + comboOptions.forEach((currentOption, optionIndex) => { const smallerCombos = combineWithRepetitions( comboOptions.slice(optionIndex), comboLength - 1, @@ -24,7 +22,7 @@ export default function combineWithRepetitions(comboOptions, comboLength) { smallerCombos.forEach((smallerCombo) => { combos.push([currentOption].concat(smallerCombo)); }); - } + }); return combos; } diff --git a/src/algorithms/sets/combinations/combineWithoutRepetitions.js b/src/algorithms/sets/combinations/combineWithoutRepetitions.js index 8f712b51..56c1e8fe 100644 --- a/src/algorithms/sets/combinations/combineWithoutRepetitions.js +++ b/src/algorithms/sets/combinations/combineWithoutRepetitions.js @@ -13,9 +13,7 @@ export default function combineWithoutRepetitions(comboOptions, comboLength) { // Eliminate characters one by one and concatenate them to // combinations of smaller lengths. - for (let optionIndex = 0; optionIndex <= (comboOptions.length - comboLength); optionIndex += 1) { - const currentOption = comboOptions[optionIndex]; - + comboOptions.forEach((currentOption, optionIndex) => { const smallerCombos = combineWithoutRepetitions( comboOptions.slice(optionIndex + 1), comboLength - 1, @@ -24,7 +22,7 @@ export default function combineWithoutRepetitions(comboOptions, comboLength) { smallerCombos.forEach((smallerCombo) => { combos.push([currentOption].concat(smallerCombo)); }); - } + }); return combos; } diff --git a/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js b/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js index 2984b7c9..0d53def1 100644 --- a/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js +++ b/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js @@ -2,9 +2,6 @@ import permutateWithRepetitions from '../permutateWithRepetitions'; describe('permutateWithRepetitions', () => { it('should permutate string with repetition', () => { - const permutations0 = permutateWithRepetitions([]); - expect(permutations0).toEqual([]); - const permutations1 = permutateWithRepetitions(['A']); expect(permutations1).toEqual([ ['A'], diff --git a/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js b/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js deleted file mode 100644 index 62b41232..00000000 --- a/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import permutateWithRepetitionsRecursive from '../permutateWithRepetitionsRecursive'; - -describe('permutateWithRepetitionsRecursive', () => { - it('should permutate string with repetition', () => { - const permutations0 = permutateWithRepetitionsRecursive([]); - expect(permutations0).toEqual([]); - - const permutations1 = permutateWithRepetitionsRecursive(['A']); - expect(permutations1).toEqual([ - ['A'], - ]); - - const permutations2 = permutateWithRepetitionsRecursive(['A', 'B']); - expect(permutations2).toEqual([ - ['A', 'A'], - ['A', 'B'], - ['B', 'A'], - ['B', 'B'], - ]); - - const permutations3 = permutateWithRepetitionsRecursive(['A', 'B', 'C']); - expect(permutations3).toEqual([ - ['A', 'A', 'A'], - ['A', 'A', 'B'], - ['A', 'A', 'C'], - ['A', 'B', 'A'], - ['A', 'B', 'B'], - ['A', 'B', 'C'], - ['A', 'C', 'A'], - ['A', 'C', 'B'], - ['A', 'C', 'C'], - ['B', 'A', 'A'], - ['B', 'A', 'B'], - ['B', 'A', 'C'], - ['B', 'B', 'A'], - ['B', 'B', 'B'], - ['B', 'B', 'C'], - ['B', 'C', 'A'], - ['B', 'C', 'B'], - ['B', 'C', 'C'], - ['C', 'A', 'A'], - ['C', 'A', 'B'], - ['C', 'A', 'C'], - ['C', 'B', 'A'], - ['C', 'B', 'B'], - ['C', 'B', 'C'], - ['C', 'C', 'A'], - ['C', 'C', 'B'], - ['C', 'C', 'C'], - ]); - - const permutations4 = permutateWithRepetitionsRecursive(['A', 'B', 'C', 'D']); - expect(permutations4.length).toBe(4 * 4 * 4 * 4); - }); -}); diff --git a/src/algorithms/sets/permutations/permutateWithRepetitions.js b/src/algorithms/sets/permutations/permutateWithRepetitions.js index 25d6fcaf..90502d29 100644 --- a/src/algorithms/sets/permutations/permutateWithRepetitions.js +++ b/src/algorithms/sets/permutations/permutateWithRepetitions.js @@ -1,42 +1,30 @@ /** * @param {*[]} permutationOptions + * @param {number} permutationLength * @return {*[]} */ -export default function permutateWithRepetitions(permutationOptions) { - // There is no permutations for empty array. - if (!permutationOptions || permutationOptions.length === 0) { - return []; +export default function permutateWithRepetitions( + permutationOptions, + permutationLength = permutationOptions.length, +) { + if (permutationLength === 1) { + return permutationOptions.map(permutationOption => [permutationOption]); } - // There is only one permutation for the 1-element array. - if (permutationOptions.length === 1) { - return [permutationOptions]; - } + // Init permutations array. + const permutations = []; - // Let's create initial set of permutations. - let previousPermutations = permutationOptions.map(option => [option]); - let currentPermutations = []; - let permutationSize = 1; + // Go through all options and join it to the smaller permutations. + permutationOptions.forEach((currentOption) => { + const smallerPermutations = permutateWithRepetitions( + permutationOptions, + permutationLength - 1, + ); - // While the size of each permutation is less then or equal to options length... - while (permutationSize < permutationOptions.length) { - // Reset all current permutations. - currentPermutations = []; + smallerPermutations.forEach((smallerPermutation) => { + permutations.push([currentOption].concat(smallerPermutation)); + }); + }); - for (let permIndex = 0; permIndex < previousPermutations.length; permIndex += 1) { - for (let optionIndex = 0; optionIndex < permutationOptions.length; optionIndex += 1) { - let currentPermutation = previousPermutations[permIndex]; - currentPermutation = currentPermutation.concat([permutationOptions[optionIndex]]); - currentPermutations.push(currentPermutation); - } - } - - // Make current permutations to be the previous ones. - previousPermutations = currentPermutations.slice(0); - - // Increase permutation size counter. - permutationSize += 1; - } - - return currentPermutations; + return permutations; } diff --git a/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js b/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js deleted file mode 100644 index f379c7ce..00000000 --- a/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @param {*[]} permutationOptions - * @param {number} permutationLength - * @param {*[]} currentPermutation - * @param {*[][]} permutations - * @return {*[]} - */ -export default function permutateWithRepetitionsRecursive( - permutationOptions, - permutationLength = permutationOptions.length || 0, - currentPermutation = [], - permutations = [], -) { - // If initial options are null or empty then return empty array. - if (!permutationOptions || !permutationOptions.length) { - return []; - } - - // If no more iterations required then add current permutation to permutations array. - if (permutationLength === 0) { - permutations.push(currentPermutation); - - return permutations; - } - - // Recursively find permutations and store in permutations array. - permutationOptions.forEach((permutationOption) => { - permutateWithRepetitionsRecursive( - permutationOptions, - permutationLength - 1, - currentPermutation.concat([permutationOption]), - permutations, - ); - }); - - return permutations; -}