How can I produce all of the combinations of the values in N number of JavaScript arrays of variable lengths?
Let's say I have N number of JavaScript arrays, e.g.
var first = ['a', 'b', 'c', 'd'];
var second = ['e'];
var third = ['f', 'g', 'h', 'i', 'j'];
(Three arrays in this example, but its N number of arrays for the problem.)
And I want to output all the combinations of their values, to produce
aef
aeg
aeh
aei
aej
bef
beg
....
dej
EDIT: Here's the version I got working, using ffriend's accepted answer as the basis.
var allArrays = [['a', 'b'], ['c', 'z'], ['d', 'e', 'f']];
function allPossibleCases(arr) {
if (arr.length === 0) {
return [];
}
else if (arr.length ===1){
return arr[0];
}
else {
var result = [];
var allCasesOfRest = allPossibleCases(arr.slice(1)); // recur with the rest of array
for (var c in allCasesOfRest) {
for (var i = 0; i < arr[0].length; i++) {
result.push(arr[0][i] + allCasesOfRest[c]);
}
}
return result;
}
}
var results = allPossibleCases(allArrays);
//outputs ["acd", "bcd", "azd", "bzd", "ace", "bce", "aze", "bze", "acf", "bcf", "azf", "bzf"]
This is not permutations, see permutations definitions from Wikipedia.
But you can achieve this with recursion:
var allArrays = [
['a', 'b'],
['c'],
['d', 'e', 'f']
]
function allPossibleCases(arr) {
if (arr.length == 1) {
return arr[0];
} else {
var result = [];
var allCasesOfRest = allPossibleCases(arr.slice(1)); // recur with the rest of array
for (var i = 0; i < allCasesOfRest.length; i++) {
for (var j = 0; j < arr[0].length; j++) {
result.push(arr[0][j] + allCasesOfRest[i]);
}
}
return result;
}
}
console.log(allPossibleCases(allArrays))
You can also make it with loops, but it will be a bit tricky and will require implementing your own analogue of stack.
I suggest a simple recursive generator function as follows:
// Generate cartesian product of given iterables:
function* cartesian(head, ...tail) {
let remainder = tail.length ? cartesian(...tail) : [[]];
for (let r of remainder) for (let h of head) yield [h, ...r];
}
// Example:
const first = ['a', 'b', 'c', 'd'];
const second = ['e'];
const third = ['f', 'g', 'h', 'i', 'j'];
console.log(...cartesian(first, second, third));
You don't need recursion, or heavily nested loops, or even to generate/store the whole array of permutations in memory.
Since the number of permutations is the product of the lengths of each of the arrays (call this numPerms
), you can create a function getPermutation(n)
that returns a unique permutation between index 0
and numPerms - 1
by calculating the indices it needs to retrieve its characters from, based on n
.
How is this done? If you think of creating permutations on arrays each containing: [0, 1, 2, ... 9] it's very simple... the 245th permutation (n=245) is "245", rather intuitively, or:
arrayHundreds[Math.floor(n / 100) % 10]
+ arrayTens[Math.floor(n / 10) % 10]
+ arrayOnes[Math.floor(n / 1) % 10]
The complication in your problem is that array sizes differ. We can work around this by replacing the n/100
, n/10
, etc... with other divisors. We can easily pre-calculate an array of divisors for this purpose. In the above example, the divisor of 100 was equal to arrayTens.length * arrayOnes.length
. Therefore we can calculate the divisor for a given array to be the product of the lengths of the remaining arrays. The very last array always has a divisor of 1. Also, instead of modding by 10, we mod by the length of the current array.
Example code is below:
var allArrays = [first, second, third, ...];
// Pre-calculate divisors
var divisors = [];
for (var i = allArrays.length - 1; i >= 0; i--) {
divisors[i] = divisors[i + 1] ? divisors[i + 1] * allArrays[i + 1].length : 1;
}
function getPermutation(n) {
var result = "", curArray;
for (var i = 0; i < allArrays.length; i++) {
curArray = allArrays[i];
result += curArray[Math.floor(n / divisors[i]) % curArray.length];
}
return result;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With