From 19f4cc70d3317b695be487392da0c4e0207ad399 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 13 Jun 2018 08:15:21 +0300 Subject: [PATCH] Add recursive way of generating permutations with repetitions. --- .../__test__/permutateWithRepetitions.test.js | 51 ++++++++++++++++++- .../permutateWithRepetitionsRecursive.test.js | 51 ++++++++++++++++++- .../testPermutateWithRepetitionsFn.js | 51 ------------------- .../permutateWithRepetitionsRecursive.js | 41 +++++++++------ 4 files changed, 124 insertions(+), 70 deletions(-) delete mode 100644 src/algorithms/sets/permutations/__test__/testPermutateWithRepetitionsFn.js diff --git a/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js b/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js index 6cf99eef..2984b7c9 100644 --- a/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js +++ b/src/algorithms/sets/permutations/__test__/permutateWithRepetitions.test.js @@ -1,8 +1,55 @@ import permutateWithRepetitions from '../permutateWithRepetitions'; -import testPermutateWithRepetitionsFn from './testPermutateWithRepetitionsFn'; describe('permutateWithRepetitions', () => { it('should permutate string with repetition', () => { - testPermutateWithRepetitionsFn(permutateWithRepetitions); + const permutations0 = permutateWithRepetitions([]); + expect(permutations0).toEqual([]); + + const permutations1 = permutateWithRepetitions(['A']); + expect(permutations1).toEqual([ + ['A'], + ]); + + const permutations2 = permutateWithRepetitions(['A', 'B']); + expect(permutations2).toEqual([ + ['A', 'A'], + ['A', 'B'], + ['B', 'A'], + ['B', 'B'], + ]); + + const permutations3 = permutateWithRepetitions(['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 = permutateWithRepetitions(['A', 'B', 'C', 'D']); + expect(permutations4.length).toBe(4 * 4 * 4 * 4); }); }); diff --git a/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js b/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js index b4799b7a..62b41232 100644 --- a/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js +++ b/src/algorithms/sets/permutations/__test__/permutateWithRepetitionsRecursive.test.js @@ -1,8 +1,55 @@ import permutateWithRepetitionsRecursive from '../permutateWithRepetitionsRecursive'; -import testPermutateWithRepetitionsFn from './testPermutateWithRepetitionsFn'; describe('permutateWithRepetitionsRecursive', () => { it('should permutate string with repetition', () => { - testPermutateWithRepetitionsFn(permutateWithRepetitionsRecursive); + 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/__test__/testPermutateWithRepetitionsFn.js b/src/algorithms/sets/permutations/__test__/testPermutateWithRepetitionsFn.js deleted file mode 100644 index c3c14daa..00000000 --- a/src/algorithms/sets/permutations/__test__/testPermutateWithRepetitionsFn.js +++ /dev/null @@ -1,51 +0,0 @@ -export default function testPermutateWithRepetitionsFn(fn) { - const permutations0 = fn([]); - expect(permutations0).toEqual([]); - - const permutations1 = fn(['A']); - expect(permutations1).toEqual([ - ['A'], - ]); - - const permutations2 = fn(['A', 'B']); - expect(permutations2).toEqual([ - ['A', 'A'], - ['A', 'B'], - ['B', 'A'], - ['B', 'B'], - ]); - - const permutations3 = fn(['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 = fn(['A', 'B', 'C', 'D']); - expect(permutations4.length).toBe(4 * 4 * 4 * 4); -} diff --git a/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js b/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js index b487efc7..f379c7ce 100644 --- a/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js +++ b/src/algorithms/sets/permutations/permutateWithRepetitionsRecursive.js @@ -1,26 +1,37 @@ /** * @param {*[]} permutationOptions + * @param {number} permutationLength + * @param {*[]} currentPermutation + * @param {*[][]} permutations * @return {*[]} */ export default function permutateWithRepetitionsRecursive( - options, - n = options.length || 0, - prefix = [], - perms = [], + permutationOptions, + permutationLength = permutationOptions.length || 0, + currentPermutation = [], + permutations = [], ) { - // If initial options are null or empty then return empty array - if (!options || !options.length) return []; - - // If no more iterations then add current prefix to perms array - if (n === 0) { - perms.push(prefix); - return perms; + // If initial options are null or empty then return empty array. + if (!permutationOptions || !permutationOptions.length) { + return []; } - // Recursively find permutations and store in perms array - options.forEach((option) => { - permutateWithRepetitionsRecursive(options, n - 1, prefix.concat([option]), perms); + // 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 perms; + return permutations; }