Count the number of items in each category within a JavaScript object

Viewed 585

I have an array containing several hundred objects, each of which has a category. I wish to return an object that lists out the categories with a count of the number of items for each category.

const arr = [
    {id: 1, name: 'ford', category: 'vehicle'},
    {id: 2, name: 'pig', category: 'animal'},
    {id: 3, name: 'dog', category: 'animal'},
    {id: 4, name: 'chev', category: 'vehicle'},
    {id: 5, name: 'cat', category: 'animal'},
    {id: 6, name: 'jeep', category: 'vehicle'},
    {id: 7, name: 'honda', category: 'vehicle'}
]

How would I loop through the object and create a new object that contains just the two categories and how many of each per category?

Desired output:

{vehicle: 4, animal: 3}

Code:

const arr = [
    {id: 1, name: 'ford', category: 'vehicle'},
    {id: 2, name: 'pig', category: 'animal'},
    {id: 3, name: 'dog', category: 'animal'},
    {id: 4, name: 'chev', category: 'vehicle'},
    {id: 5, name: 'cat', category: 'animal'},
    {id: 6, name: 'jeep', category: 'vehicle'},
    {id: 7, name: 'honda', category: 'vehicle'}
]

const final = {};
arr.forEach((v) => {
  const tst = v.category;
  console.log(tst);
  if (tst in final){
     console.log('found one');
  }
});

//console.log(final);

4 Answers

You can use reduce

const arr = [
    {id: 1, name: 'ford', category: 'vehicle'},
    {id: 2, name: 'pig', category: 'animal'},
    {id: 3, name: 'dog', category: 'animal'},
    {id: 4, name: 'chev', category: 'vehicle'},
    {id: 5, name: 'cat', category: 'animal'},
    {id: 6, name: 'jeep', category: 'vehicle'},
    {id: 7, name: 'honda', category: 'vehicle'}
]


const categories = arr.reduce((acc, cur) => {
   acc[cur.category] = (acc[cur.category] || 0) + 1
   return acc;
}, {})

console.log(categories)

It looks like the category will always exist, so you don't need to check whether it exists, but what it contains; take what it contains and increment that property on the final object:

const arr = [
    {id: 1, name: 'ford', category: 'vehicle'},
    {id: 2, name: 'pig', category: 'animal'},
    {id: 3, name: 'dog', category: 'animal'},
    {id: 4, name: 'chev', category: 'vehicle'},
    {id: 5, name: 'cat', category: 'animal'},
    {id: 6, name: 'jeep', category: 'vehicle'},
    {id: 7, name: 'honda', category: 'vehicle'}
]

const final = {};
for (const { category } of arr) {
  final[category] = (final[category] || 0) + 1;
};
console.log(final);

You have the right idea regarding looping over the array and checking if the category was already encountered. What you're missing is initializing a counter when you find a new category and incrementing it the next time that category is encountered:

const arr = [
    {id: 1, name: 'ford', category: 'vehicle'},
    {id: 2, name: 'pig', category: 'animal'},
    {id: 3, name: 'dog', category: 'animal'},
    {id: 4, name: 'chev', category: 'vehicle'},
    {id: 5, name: 'cat', category: 'animal'},
    {id: 6, name: 'jeep', category: 'vehicle'},
    {id: 7, name: 'honda', category: 'vehicle'}
]

const final = {};
arr.forEach((v) => {
  const cat = v.category;
  if (cat in final) {
     final[cat]++;
  } else {
     final[cat] = 1;
  }
});

console.log(final);

const arr = [
  { id: 1, name: 'ford', category: 'vehicle' },
  { id: 2, name: 'pig', category: 'animal' },
  { id: 3, name: 'dog', category: 'animal' },
  { id: 4, name: 'chev', category: 'vehicle' },
  { id: 5, name: 'cat', category: 'animal' },
  { id: 6, name: 'jeep', category: 'vehicle' },
  { id: 7, name: 'honda', category: 'vehicle' },
]

// this will hold the results
const result = {}

for (const item of arr) {
  // we have not encountered such category before
  if (result[item.category] === undefined) {
    // setting this category to 1
    result[item.category] = 1
    
  // we encountered such category before
  } else { 
    // addint +1 to it
    result[item.category] += 1
  }
}

console.log(result)

Related