I tried to find a solution to my problem but couldn't find one, so I have an array of objects (products), each product has a category property and I want to group the products by categories. I managed to do that using reduce() but now I would need to render the category name first and then the products in that category.
Example:
const products = [
{id: 1, category: 'Burgers', name: 'Burger'},
{id: 2, category: 'Burgers', name: 'Cheeseburger'},
{id: 3, category: 'Meals', name: 'Burger meal'},
{id: 4, category: 'Meals', name: 'Cheeseburger meal'}
]
I need to group these products by category and I did that with reduce()
const menu = products.reduce((menu, product) => {
if (menu[product.category] == null) menu[product.category] = []
menu[product.category].push(product)
return menu
}, [])
So now my result is
[Burgers: Array(2), Meals: Array(2)]
But I would want to render those with map() so how can I do that? Or how can I change the result? I would want the result to be like
Categories: [
{
0:
name: 'Burgers',
products: Array(2)
},
{
1:
name: 'Meals',
products: Array(2)
}
]
That way I could render that array with map like
<div>
{menu.map((c, index) =>
<Category key={index} name={c.name} products={c.products} />
)}
</div>
CodePudding user response:
const products = [
{id: 1, category: 'Burgers', name: 'Burger'},
{id: 2, category: 'Burgers', name: 'Cheeseburger'},
{id: 3, category: 'Meals', name: 'Burger meal'},
{id: 4, category: 'Meals', name: 'Cheeseburger meal'}
]
const menu = products.reduce((acc, product)=> {
const categoryIndex = acc.findIndex(item => item.name == product.category);
if(categoryIndex > -1){
acc[categoryIndex].products.push(product);
}else {
acc.push({ name: product.category, products: [product] })
};
return acc;
}, []);
console.log(menu)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
At first, I was only answering the pure javascript question about how to groupby
products.reduce((prev, curr) => {
if(!prev.categories.hasOwnProperty(curr.category)) prev.categories[curr.category] = prev.count
const index = prev.categories[curr.category]
if(!Array.isArray(prev.menu[index])) prev.menu[index] = []
prev.menu[index].push(curr)
return prev
}, {count: 0, menu: [], categories:{}}).menu
From there, I guess your map would look like this:
<div>
{menu.forEach((c, i) =>
<Category key={i} name={c[0].category} products={c} />
)}
</div>