I am working on an eCommerce javascript app, and trying to create product variants based on attributes.
If a product has attributes:
Size: Small, Medium, Large
Color: Red, Blue
Material: Cotton, Wool
I want result like this [{color: "Red", sizes: "Small"}, {color: "Blue", sizes: "Small"}, {color: "Red", sizes: "Medium"}, {color: "Blue", sizes: "Medium"}, {color: "Red", sizes: "Large"}, {color: "Blue", sizes: "Large"}]
I've done this, but is there an easy way to do this?
Here is the code that I've done:
let attributes = {
color: ['Red', 'Blue'],
sizes: ['Small', 'Medium', 'Large'],
material: ['Cotton', 'Wool']
};
let getProducts = (arrays) => {
if (arrays.length === 0) {
return [[]];
}
let results = [];
getProducts(arrays.slice(1)).forEach((product) => {
arrays[0].forEach((value) => {
results.push([value].concat(product));
});
});
return results;
};
let getAllCombinations = (attributes) => {
let attributeNames = Object.keys(attributes);
// console.log(attributeNames);
let attributeValues = attributeNames.map((name) => attributes[name]);
// console.log(attributeValues);
return getProducts(attributeValues).map((product) => {
obj = {};
attributeNames.forEach((name, i) => {
obj[name] = product[i];
});
return obj;
});
};
let binations = getAllCombinations(attributes);
console.log(binations.length);
console.log(binations);
I am working on an eCommerce javascript app, and trying to create product variants based on attributes.
If a product has attributes:
Size: Small, Medium, Large
Color: Red, Blue
Material: Cotton, Wool
I want result like this [{color: "Red", sizes: "Small"}, {color: "Blue", sizes: "Small"}, {color: "Red", sizes: "Medium"}, {color: "Blue", sizes: "Medium"}, {color: "Red", sizes: "Large"}, {color: "Blue", sizes: "Large"}]
I've done this, but is there an easy way to do this?
Here is the code that I've done:
let attributes = {
color: ['Red', 'Blue'],
sizes: ['Small', 'Medium', 'Large'],
material: ['Cotton', 'Wool']
};
let getProducts = (arrays) => {
if (arrays.length === 0) {
return [[]];
}
let results = [];
getProducts(arrays.slice(1)).forEach((product) => {
arrays[0].forEach((value) => {
results.push([value].concat(product));
});
});
return results;
};
let getAllCombinations = (attributes) => {
let attributeNames = Object.keys(attributes);
// console.log(attributeNames);
let attributeValues = attributeNames.map((name) => attributes[name]);
// console.log(attributeValues);
return getProducts(attributeValues).map((product) => {
obj = {};
attributeNames.forEach((name, i) => {
obj[name] = product[i];
});
return obj;
});
};
let binations = getAllCombinations(attributes);
console.log(binations.length);
console.log(binations);
Share
Improve this question
edited Mar 7, 2021 at 21:27
Muhammad Taseen
asked Mar 7, 2021 at 21:03
Muhammad TaseenMuhammad Taseen
5791 gold badge7 silver badges22 bronze badges
2 Answers
Reset to default 5try this:
let attributes = {
color: ['Red', 'Blue'],
sizes: ['Small', 'Medium', 'Large'],
material: ['Cotton', 'Wool'],
gender: ['Men', 'Women'],
type: ['Casual', 'Sport']
};
let attrs = [];
for (const [attr, values] of Object.entries(attributes))
attrs.push(values.map(v => ({[attr]:v})));
attrs = attrs.reduce((a, b) => a.flatMap(d => b.map(e => ({...d, ...e}))));
console.log(attrs);
If you don't need to support ie directly you could use a bination of array.prototype.flatMap() and array.prototype.map().
let attributes = {
color: ["Red", "Blue"],
sizes: ["Small", "Medium", "Large"],
};
const bo = attributes.color.flatMap((d) =>
attributes.sizes.map((v) => ({ color: d, sizes: v }))
);
console.log(bo);
A more generic solution which uses cartesian product of arrays in vanilla JS could look like this.
let attributes = {
color: ['Red', 'Blue'],
sizes: ['Small', 'Medium', 'Large'],
material: ['Cotton', 'Wool']
};
const f = (a, b) => [].concat(...a.map(d => b.map(e => [].concat(d, e))));
const cartesian = (a, b, ...c) => (b ? cartesian(f(a, b), ...c) : a);
const resArr = cartesian(attributes.color, attributes.sizes, attributes.material);
const resObj = resArr.map((x)=>({color:x[0], sizes:x[1], material: x[2]}))
console.log(resObj);