I created this function which allows me to have all combinations from a list of lists:
const cartesian = (...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));
I have four list for example:
var l1 = ["A","B"]
var l2 = ["C"]
var l3 = ["D","E"] #optional
var l4 = ["F","G"] #optional
var list = [l1,l2,l3,l4]
Obviusly with this function i have all combination of the lists but i want to get all combinations with optnional lists. For Example the desired output is:
1. ["A","C"]
2. ["B","C"]
3. ["A","C","D"]
4. ["A","C","E"]
5. ["B","C","D"]
6. ["B","C","E"]
7. ["A","C","F"]
8. ["A","C","G"]
9. ["B","C","F"]
10. ["B","C","G"]
11. ["A","C","D","F"]
12. ["A","C","D","G"]
13. ["A","C","E","F"]
14. ["A","C","E","G"]
15. ["B","C","D","F"]
16. ["B","C","D","G"]
17. ["B","C","E","F"]
18. ["B","C","E","G"]
How can i get this output?
CodePudding user response:
Your cartesian function is tailor made for exactly four input arrays. I would make a generic version that can take any number of arrays.
I would then pass the optional flags as arguments as well -- maybe as a second array -- and use that info to also generate combinations that exclude elements from the corresponding array.
Here is a recursive generator to do the job:
function* cartesian([first, ...rest], [isOptional, ...isRestOptional]) {
if (!first) return yield [];
let restResults = [...cartesian(rest, isRestOptional)];
if (isOptional) yield* restResults;
for (const value of first) {
for (const result of restResults) {
yield [value, ...result];
}
}
}
// demo run
const resultsIter = cartesian([["A","B"], ["C"], ["D","E"], ["F","G"]], [0, 0, 1, 1]);
for (let result of resultsIter) console.log(...result);
The output has a different order, but it gives you all combinations.