let constraints = {
key1: ['possible value1' , 'possible value2'],
key2: [2, 4, 7, 1],
key3: ["foo", "bar"],
};
let result = Object.keys(constraints).reduce(
(acc, key) =>
acc.map(a1 =>
constraints[key].map(a2 =>
a1.concat([a2])
)
).reduce((e1, e2) => e1.concat(e2)),
[[]]
);
console.log(JSON.stringify(result));
First we make sure we know how to make all concatenations of elements of two arrays, if the first contains arrays (all arrays produced by some set of constraints) and the second single elements (a new constraint). (e.g. [["possible value1"], ["possible value2"]
and [1, 2]
). We map one array, map the other array, then stick them together (the a1
and a2
maps, a1.concat([a2])
). The nested map
will produce a two-level array, so we'll just concatenate all arrays from the single level (the inner reduce
).
Note that if we concatenate an empty array to an array, the array is unchanged; thus, we could introduce another constraint, an empty one: []
. If we combine all the arrays that correspond to this constraint, [[]]
, with ["possible value1", "possible value2"]
, we still get the same set. This is the starting value for our outer reduce
: starting with this "null element", we can concatenate other constraints as described above.
EDIT: made prettier:
let constraints = {
key1: ['possible value1' , 'possible value2'],
key2: [2, 4, 7, 1],
key3: ["foo", "bar"],
};
const unconstrainedPossibilities = [[]];
const flatten = array => array.reduce((a1, a2) => a1.concat(a2));
const addConstraint = (possibilities, constraint) =>
flatten(
possibilities.map(possibility =>
constraint.map(constraintValue =>
possibility.concat([constraintValue])
)
)
);
const possibilitiesFor = constraints =>
constraints.reduce(
(possibilities, constraint) => addConstraint(possibilities, constraint),
unconstrainedPossibilities
);
let possibilities = possibilitiesFor(Object.values(constraints));
console.log(JSON.stringify(possibilities));