1

How do you groupBy array of objects based on specific properties in vanilla javascript? For example this given:

const products = [
  {
    category: "Sporting Goods",
    price: "$49.99",
    stocked: true,
    name: "Football"
  },
  {
    category: "Sporting Goods",
    price: "$9.99",
    stocked: true,
    name: "Baseball"
  },
  {
    category: "Sporting Goods",
    price: "$29.99",
    stocked: false,
    name: "Basketball"
  },
  {
    category: "Electronics",
    price: "$99.99",
    stocked: true,
    name: "iPod Touch"
  },
  {
    category: "Electronics",
    price: "$399.99",
    stocked: false,
    name: "iPhone 5"
  },
  { category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" }
];

i want to run a reduce function that would result to a new array of objects like this:

Intended Output:

const categorize = [
  {
    category:"Sporting Goods",
    products: [
      {
        name:"Football",
        price: "$49.99",
        stocked: true
      },
      {
        name:"Baseball",
        price: "$9.99",
        stocked: true
      },
      {
        name:"Basketball",
        price: "$29.99",
        stocked: true
      }
    ]
  },
  {
    category: "Electronics",
    products: [
      {
        name: "iPod Touch",
        price: "$99.99",
        stocked: true
      },
      {
        name: "iPhone 5",
        price: "$399.99",
        stocked: false
      },
      {
        name: "Nexus 7",
        price: "$199.99",
        stocked: true
      }
    ]
  }
]

i based my solution from the tutorial here: https://www.consolelog.io/group-by-in-javascript/ using the reduce function.

Here's my code:

const groupBy = (arr,prop)=>{
  return arr.reduce((groups,item)=>{
    let val = item[prop];
    groups[val] = groups[val]||[];
    groups[val].push(item);
    return groups
  },{});
}

const categorize = groupBy(products,'category');
console.log(categorize);

/* returns an Object like
    Object {Sporting Goods: Array[3], Electronics: Array[3]}
   however it's not the intended output.
*/

I tried to return Object.values(obj) or Object.entries(obj) inside the groupBy function but it just returns an array of 2 arrays like [Array[3],Array[3]] and if i set the initial value (2nd parameter of reduce) to empty [] instead of {}, the output is just an empty array. Need help, thanks!

3
  • Are you ok to use any third party library like underscore.js ? Commented Aug 16, 2019 at 9:59
  • 1
    this may be the duplicate of stackoverflow.com/questions/14446511/… Commented Aug 16, 2019 at 9:59
  • @Sohan i want it to be vanilla as much as possible. Commented Aug 16, 2019 at 10:01

2 Answers 2

4

Because you want an array containing objects (rather than just an array of plain values), create a { category, products: [] } object if it doesn't exist in the accumulator:

const products=[{category:"Sporting Goods",price:"$49.99",stocked:!0,name:"Football"},{category:"Sporting Goods",price:"$9.99",stocked:!0,name:"Baseball"},{category:"Sporting Goods",price:"$29.99",stocked:!1,name:"Basketball"},{category:"Electronics",price:"$99.99",stocked:!0,name:"iPod Touch"},{category:"Electronics",price:"$399.99",stocked:!1,name:"iPhone 5"},{category:"Electronics",price:"$199.99",stocked:!0,name:"Nexus 7"}];

const output = Object.values(
  products.reduce((a, { category, ...item }) => {
    if (!a[category]) {
      a[category] = { category, products: [] };
    }
    a[category].products.push(item);
    return a;
  }, {})
);
console.log(output);

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks much! Please can you explain your answer in a little more understandable for beginners. Thanks again.
0
    function (){
var map = {};
products.forEach((p) => {
  if (map[p.category]) {
 var c = p.category;
delete p.category;
  map[c].push(p);
} else {
 var c = p.category;
delete p.category;
map[c]=[c]
}
});

Object.keys(map).forEach((m) => {
ans.push({category:m, products: map[m]})
})

}

you can collect in one go products and map them. Then make your resultinng array

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.