Reputation: 33
How would I go about transforming this shape of data below using Javascript (es6 is fine).
From:
[
{
name: "Color",
options: [{ value: "Gold" }, { value: "Space grey" }]
},
{
name: "Size",
options: [{ value: 32 }, { value: 64 }]
},
{
name: "Width",
options: [{ value: 100 }, { value: 200 }]
}
]
To:
[
{
properties: {
Color: "Gold",
Size: 32,
Width: 100
}
},
{
properties: {
Color: "Gold",
Size: 32,
Width: 200
}
},
{
properties: {
Color: "Gold",
Size: 64,
Width: 100
}
},
{
properties: {
Color: "Gold",
Size: 64,
Width: 200
}
},
{
properties: {
Color: "Space grey",
Size: 32,
Width: 100
}
},
{
properties: {
Color: "Space grey",
Size: 32,
Width: 200
}
},
{
properties: {
Color: "Space grey",
Size: 64,
Width: 100
}
},
{
properties: {
Color: "Space grey",
Size: 64,
Width: 200
}
}
]
The second shape is every possible combination of options of the first shape.
I'm trying to build a product form that can handle products that have variants e.g. Color, Size, Material etc. Each of those variants can have multiple options. e.g. For Color, they could be Red, Blue, Orange etc. To get this to work I think I need to get a list that generates all possible combinations so that I can attach a price to each.
Would appreciate any help as I'm stumped :(
Below is what I tried. But its the wrong shape.
let variants = [{
name: "Color",
options: [{
value: "Gold"
}, {
value: "Space grey"
}]
},
{
name: "Size",
options: [{
value: "32"
}, {
value: "64"
}]
},
{
name: "Width",
options: [{
value: "100"
}, {
value: "200"
}]
}
]
const [primaryOption, ...otherOptions] = variants
let options = []
primaryOption.options.map(x => {
otherOptions.map(y => {
y.options.map(z => {
options = [
...options,
{
properties: {
[primaryOption.name]: x.value,
[y.name]: z.value
}
}
]
})
})
})
console.log(options)
Upvotes: 2
Views: 249
Reputation: 386550
You could take the cartesian product by iterating the outer array and take the inner array for the values to append objects.
function getCartesian(array) {
return array.reduce((r, { name, options }) => {
var temp = [];
r.forEach(({ property }) =>
options.forEach(({ value }) => temp.push({ property: Object.assign({}, property, { [name]: value }) }))
);
return temp;
}, [{}]);
}
var data = [{ name: "Color", options: [{ value: "Gold" }, { value: "Space grey" }] }, { name: "Size", options: [{ value: 32 }, { value: 64 }] }, { name: "Width", options: [{ value: 100 }, { value: 200 }] }];
console.log(getCartesian(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 12619
let variants = [{
name: "Color",
options: [{
value: "Gold"
}, {
value: "Space grey"
}]
},
{
name: "Size",
options: [{
value: 32
}, {
value: 64
}]
},
{
name: "Width",
options: [{
value: 100
}, {
value: 200
}]
}
];
let endIndex = variants[0].options.length;
let result = [];
for (let i = 0; i < endIndex; i++) {
variants.forEach(x => {
result[i] = result[i] || {properties:{}};
result[i].properties[x.name] = x.options[i].value;
});
}
console.log(result);
Upvotes: 0
Reputation: 138257
let result = [{}];
for(const {name, options} of input) {
const previous = result;
result = [];
for(const {value} of options) {
for(const prev of previous)
result.push({ ...prev, [name]: value });
}
}
Just use a nested loop to go over all values, and build up a new array with them.
Upvotes: 3