Reputation: 1058
I have an array of objects I am trying to find all the combinations for. I have got some code that finds all the combinations, however it only find the number of combinations based on the length of the input array.
For example if I use the below array and with the function below I get 27 potential combinations, however that doesn't include elements on their own or in twos.
[
[{ optionName: "red" },{ optionName: "blue" },{ optionName: "green" }],
[{ optionName: "S" },{ optionName: "L" },{ optionName: "XL" }],
[{ optionName: "spotted" },{ optionName: "striped" },{ optionName: "lined" }],
]
For example I get combinations that look like this:
[{ optionName: "red" },{ optionName: "L" },{ optionName: "spotted" }]
[{ optionName: "red" },{ optionName: "S" },{ optionName: "spotted" }]
[{ optionName: "red" },{ optionName: "S" },{ optionName: "lined" }]
However I want to also include combinations like:
[{ optionName: "red" }]
[{ optionName: "red" },{ optionName: "S" }]
[{ optionName: "red" },{ optionName: "L" }]
This is the code I am working with:
var r = [],
arg = arrayCombOptions,
max = arg.length - 1;
function helper(arr, i) {
for (var j = 0, l = arg[i].length; j < l; j++) {
var a = arr.slice(0);
a.push(arg[i][j]);
if (i == max) r.push(a);
else helper(a, i + 1);
}
}
helper([], 0);
How do I find all the combinations including individual and dual combinations?
Upvotes: 1
Views: 48
Reputation: 604
A clean and simple solution: You need to iterate through the array of arrays and for each individual array find all of the possibilities.
const addToEach = (element, arr) => [...arr, element];
const getAllPossibilitesForSingleArr = (arr) => {
let r = [];
for(let i=0;i<arr.length;i++) {
const combinationsSoFarWithNewElementAdded = r.map(ar => addToEach(arr[i],ar))
r.push(...combinationsSoFarWithNewElementAdded, [arr[i]]);
}
return r;
};
const getAllPossibilitesForArrays = arrays => arrays.map(getAllPossibilitesForSingleArr);
In order to find every possibility in a single array I have iterated through the array and in each iteration, I am expanding the result array with a new element and all combinations so far with the new element added.
You can also do it with pure functions (always better):
const getAllPossibilitesForSingleArrFunc = (arr) =>
arr.reduce((acc, curr,i) => {
const combinationsSoFarWithNewElementAdded = acc.map(ar => addToEach(arr[i],ar))
return [...acc, [arr[i]], ...combinationsSoFarWithNewElementAdded]
},[]);
const getAllPossibilitesForArraysFunc = arrays => arrays.map(getAllPossibilitesForSingleArrFunc);
Upvotes: 0
Reputation: 386654
You could add for each inner array a dummy like undefined
, generate a cartesian product, map only arrays without undefined
and slice the array from one, because the first is empty as well.
var data = [[{ optionName: "red" }, { optionName: "blue" }, { optionName: "green" }], [{ optionName: "S" }, { optionName: "L" }, { optionName: "XL" }], [{ optionName: "spotted" }, { optionName: "striped" }, { optionName: "lined" }]],
result = data
.map(a => [undefined, ...a])
.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []))
.map(a => a.filter(Boolean))
.slice(1);
console.log(result.length);
document.getElementById('out').innerHTML = JSON.stringify(result, null, 4);
<pre id="out"><pre>
Upvotes: 2