Add recursive way of generating permutations with repetitions.

This commit is contained in:
Oleksii Trekhleb 2018-06-13 08:15:21 +03:00
parent b0c55ec817
commit 19f4cc70d3
4 changed files with 124 additions and 70 deletions

View File

@ -1,8 +1,55 @@
import permutateWithRepetitions from '../permutateWithRepetitions'; import permutateWithRepetitions from '../permutateWithRepetitions';
import testPermutateWithRepetitionsFn from './testPermutateWithRepetitionsFn';
describe('permutateWithRepetitions', () => { describe('permutateWithRepetitions', () => {
it('should permutate string with repetition', () => { 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);
}); });
}); });

View File

@ -1,8 +1,55 @@
import permutateWithRepetitionsRecursive from '../permutateWithRepetitionsRecursive'; import permutateWithRepetitionsRecursive from '../permutateWithRepetitionsRecursive';
import testPermutateWithRepetitionsFn from './testPermutateWithRepetitionsFn';
describe('permutateWithRepetitionsRecursive', () => { describe('permutateWithRepetitionsRecursive', () => {
it('should permutate string with repetition', () => { 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);
}); });
}); });

View File

@ -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);
}

View File

@ -1,26 +1,37 @@
/** /**
* @param {*[]} permutationOptions * @param {*[]} permutationOptions
* @param {number} permutationLength
* @param {*[]} currentPermutation
* @param {*[][]} permutations
* @return {*[]} * @return {*[]}
*/ */
export default function permutateWithRepetitionsRecursive( export default function permutateWithRepetitionsRecursive(
options, permutationOptions,
n = options.length || 0, permutationLength = permutationOptions.length || 0,
prefix = [], currentPermutation = [],
perms = [], permutations = [],
) { ) {
// If initial options are null or empty then return empty array // If initial options are null or empty then return empty array.
if (!options || !options.length) return []; if (!permutationOptions || !permutationOptions.length) {
return [];
// If no more iterations then add current prefix to perms array
if (n === 0) {
perms.push(prefix);
return perms;
} }
// Recursively find permutations and store in perms array // If no more iterations required then add current permutation to permutations array.
options.forEach((option) => { if (permutationLength === 0) {
permutateWithRepetitionsRecursive(options, n - 1, prefix.concat([option]), perms); 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;
} }