Akllu
Akllu

Reputation: 33

Best way to group an array with property of object and how to render the result

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>

Upvotes: 1

Views: 793

Answers (2)

Saeed Shamloo
Saeed Shamloo

Reputation: 6564

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)

Upvotes: 2

roberto tom&#225;s
roberto tom&#225;s

Reputation: 4687

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>

Upvotes: 0

Related Questions