[英]How to generate in Javascript all combinations of items from multiple objects
I have an array of objects with names and options and I need all possible combinations of products.我有一组带有名称和选项的对象,我需要所有可能的产品组合。 The important part is that this array has an N number of objects with N number of options in every object.
重要的部分是这个数组在每个 object 中有 N 个对象和 N 个选项。
I tried to create some kind of recursive algorithm, but the problem is that I failed to push recursively to receive the needed data structure in the end.我尝试创建某种递归算法,但问题是我最终未能递归推送以接收所需的数据结构。 I also tried the approach from Cartesian product of multiple arrays in JavaScript but it seems it is not relevant to the output needed.
我还尝试了JavaScript 中多个 arrays 的笛卡尔积的方法,但它似乎与所需的 output 无关。
Example:例子:
input = [
{
name: "Size",
options: [ { value: "S" }, { value: "M" }, { value: "L" }, ...and so on]
},
{
name: "Color",
options: [ { value: "Red" }, { value: "White" }, { value: "Blue" }, ...and so on]
},
{
name: "Weight",
options: [ { value: "1kg" }, { value: "2kg" }, { value: "3kg" }, { value: "4kg"}, ]
},
.... and so on
];
I need to have all the possible combinations in the form of the array which itself includes an array of objects with the object's name and value.我需要以数组的形式拥有所有可能的组合,该数组本身包括具有对象名称和值的对象数组。
Example (Array of arrays):示例(数组数组):
output = [
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '1kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '2kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '3kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '4kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '1kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '2kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '3kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '4kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Blue'}, {name: 'Weight', value: '1kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Blue'}, {name: 'Weight', value: '2kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Blue'}, {name: 'Weight', value: '3kg'} ],
[ {name: 'Size', value: 'S'}, {name: 'Color', value: 'Blue'}, {name: 'Weight', value: '4kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '1kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '2kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '3kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'Red'}, {name: 'Weight', value: '4kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '1kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '2kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '3kg'} ],
[ {name: 'Size', value: 'M'}, {name: 'Color', value: 'White'}, {name: 'Weight', value: '4kg'} ],
... and so on
];
This is definitely a cartesian product question.这绝对是一个笛卡尔积问题。 The only thing is that you will need to format your input before you call the cartesian product.
唯一的问题是,在调用笛卡尔积之前,您需要格式化输入。 Here is one version, using a simple, recursive
cartesian
function.这是一个版本,使用简单的递归
cartesian
function。
const cartesian = ([xs, ...xss]) => xs = undefined? []: xss.length == 0? xs.map (x => [x]): xs.flatMap (x => cartesian (xss).map (ys => [x, ...ys])) const combine = (properties) => cartesian (properties.map (({name, options}) => options.map (({value}) => ({name, value})))) const properties = [{name: "Size", options: [ { value: "S" }, { value: "M" }, { value: "L" }, /*...and so on */]}, {name: "Color", options: [ { value: "Red" }, { value: "White" }, { value: "Blue" }, /*...and so on */]}, {name: "Weight", options: [ { value: "1kg" }, { value: "2kg" }, { value: "3kg" }, { value: "4kg"}, ]}, /*.... and so on */] console.log (JSON.stringify (combine (properties), null, 2))
.as-console-wrapper {max-height: 100%;important: top: 0}
But I find your output format quite repetitive.但我发现您的 output 格式非常重复。 I would prefer something like:
我更喜欢这样的东西:
[
{Size: "S", Color: "Red", Weight: "1kg"},
{Size: "S", Color: "Red", Weight: "2kg"},
{Size: "S", Color: "Red", Weight: "3kg"},
{Size: "S", Color: "Red", Weight: "4kg"},
{Size: "S", Color: "White", Weight: "1kg"},
// ...
{Size: "L", Color: "Blue", Weight: "4kg"},
]
and we can achieve it with just a bit more work:我们可以通过更多的工作来实现它:
const cartesian = ([xs, ...xss]) => xs = undefined? []: xss.length == 0? xs.map (x => [x]): xs.flatMap (x => cartesian (xss).map (ys => [x, ...ys])) const properties = [{name: "Size", options: [ { value: "S" }, { value: "M" }, { value: "L" }, /*...and so on */]}, {name: "Color", options: [ { value: "Red" }, { value: "White" }, { value: "Blue" }, /*...and so on */]}, {name: "Weight", options: [ { value: "1kg" }, { value: "2kg" }, { value: "3kg" }, { value: "4kg"}, ]}, /*.... and so on */] const combine = (properties) => cartesian (properties.map ( ({name, options}) => options.map (({value}) => ({[name]: value})) )).map (ps => Object.assign ({}, ...ps)) console.log (combine (properties))
.as-console-wrapper {max-height: 100%;important: top: 0}
If that version of the cartesian product does not make sense to you, this one is an alternative:如果该版本的笛卡尔积对您没有意义,则可以使用此版本:
const cartesian = ([x, ...xs]) =>
(xs || []) .reduce (
(a, b) => a .reduce (
(c, d) => [... c, ... (b .map (e => [... d, e]))],
[]
),
(x || []) .map (x => [x])
)
This is only a supplement to @Scott's already terrific answer.这只是对@Scott 已经很棒的答案的补充。 I wanted to offer two alternatives for
cartesian
-我想为
cartesian
提供两种选择 -
const cartesian = ([t, ...more]) =>
t == null
? [[]]
: t.flatMap(v => cartesian(more).map(r => [v, ...r]))
Using Scott's combine
function -使用斯科特的
combine
function -
for (const c of combine(properties))
console.log(c)
{"Size":"S","Color":"Red","Weight":"1kg"}
{"Size":"S","Color":"Red","Weight":"2kg"}
{"Size":"S","Color":"Red","Weight":"3kg"}
{"Size":"S","Color":"Red","Weight":"4kg"}
{"Size":"S","Color":"White","Weight":"1kg"}
{"Size":"S","Color":"White","Weight":"2kg"}
{"Size":"S","Color":"White","Weight":"3kg"}
{"Size":"S","Color":"White","Weight":"4kg"}
{"Size":"S","Color":"Blue","Weight":"1kg"}
{"Size":"S","Color":"Blue","Weight":"2kg"}
{"Size":"S","Color":"Blue","Weight":"3kg"}
{"Size":"S","Color":"Blue","Weight":"4kg"}
{"Size":"M","Color":"Red","Weight":"1kg"}
{"Size":"M","Color":"Red","Weight":"2kg"}
{"Size":"M","Color":"Red","Weight":"3kg"}
{"Size":"M","Color":"Red","Weight":"4kg"}
{"Size":"M","Color":"White","Weight":"1kg"}
{"Size":"M","Color":"White","Weight":"2kg"}
{"Size":"M","Color":"White","Weight":"3kg"}
{"Size":"M","Color":"White","Weight":"4kg"}
{"Size":"M","Color":"Blue","Weight":"1kg"}
{"Size":"M","Color":"Blue","Weight":"2kg"}
{"Size":"M","Color":"Blue","Weight":"3kg"}
{"Size":"M","Color":"Blue","Weight":"4kg"}
{"Size":"L","Color":"Red","Weight":"1kg"}
{"Size":"L","Color":"Red","Weight":"2kg"}
{"Size":"L","Color":"Red","Weight":"3kg"}
{"Size":"L","Color":"Red","Weight":"4kg"}
{"Size":"L","Color":"White","Weight":"1kg"}
{"Size":"L","Color":"White","Weight":"2kg"}
{"Size":"L","Color":"White","Weight":"3kg"}
{"Size":"L","Color":"White","Weight":"4kg"}
{"Size":"L","Color":"Blue","Weight":"1kg"}
{"Size":"L","Color":"Blue","Weight":"2kg"}
{"Size":"L","Color":"Blue","Weight":"3kg"}
{"Size":"L","Color":"Blue","Weight":"4kg"}
Another approach to cartesian
might look like this. cartesian
的另一种方法可能如下所示。 Generators are always a great fit for problems involving combinations and permutations -生成器总是非常适合涉及组合和排列的问题 -
function* cartesian([t, ...more]) {
if (t == null)
return yield []
for (const v of t)
for (const c of cartesian(more))
yield [v, ...c]
}
function* combine(t) {
for (const ps of cartesian(t.map(({name, options}) => options.map(({value}) => ({[name]: value})))))
yield Object.assign({}, ...ps)
}
for (const c of combine(properties))
console.log(c)
Output is identical - Output 相同 -
{"Size":"S","Color":"Red","Weight":"1kg"}
{"Size":"S","Color":"Red","Weight":"2kg"}
{"Size":"S","Color":"Red","Weight":"3kg"}
...
{"Size":"L","Color":"Blue","Weight":"2kg"}
{"Size":"L","Color":"Blue","Weight":"3kg"}
{"Size":"L","Color":"Blue","Weight":"4kg"}
Use Array.from if you would like to collect the results in an array.如果您想在数组中收集结果,请使用Array.from 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.