Reputation: 2504
I would like to generate all combinations for a template-like object which could take several children in which some define the desired output as an array. Those children can have as well children (there is virtually no limit).
const input = {
a: [true, false],
b: ['first', 'second'],
c: {
d: [true, false]
}
};
const output = [
{
a: true,
b: 'first',
c: {
d: true
}
},
{
a: true,
b: 'first',
c: {
d: false
}
},
{
a: true,
b: 'second',
c: {
d: true
}
},
{
a: true,
b: 'second',
c: {
d: false
}
},
//...
]
What could be the JavaScript function to transform the input into an output?
I tried taking the original function from this question and make it more ES compliant but this is not working when having multiple children inside the object.
function combinations(input, keyIndex = 0, current = {}, result = []) {
const keys = Object.keys(input)
const key = keys[keyIndex]
const values = input[key]
for (const index in values) {
current[key] = values[index]
if (keyIndex + 1 < keys.length) {
combinations(input, keyIndex + 1, current, result)
} else {
result.push(JSON.parse(JSON.stringify(current)))
}
}
return result;
}
Upvotes: 2
Views: 124
Reputation: 386560
You could take a recursive function which separates all key/value pairs and build a new cartesian product by iterating the values, if an array with objects call getCartesian
again and build new objects.
This works for nested objects as well.
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
var input = { a: [true, false], b: ['first', 'second'], c: { d: [true, false] } },
cartesian = getCartesian(input);
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 4