Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sum up values of same field in array of objects?

I have an array of objects

const data = [
  { category: 'shopping', amount: 50 }, 
  { category: 'rent', amount: 1000 }, 
  { category: 'groceries', amount: 20 }, 
  { category: 'shopping', amount: 50 }
]

and I am trying to sum up the amounts per category

const result = [
  { category: 'shopping', amount: 100 },
  { category: 'rent', amount: 1000 },
  { category: 'groceries', amount: 20 }
]

So far, I'm thinking of removing the 'duplicates' of categories and store them into an array

const temp = data.map((obj) => {
  return obj.category
})

const categories = [...new Set(temp)] // ['shopping','rent','groceries']

With the above, i'm thinking of doing a nested loop but after many tries, I have failed.

Any help is appreciated

like image 704
Leon Avatar asked Oct 24 '25 02:10

Leon


2 Answers

You can use reduce() to do that.

Iterate on given data and if an item with same category as current item exists, then add the amount, else add current item as a new entry.

const data = [
  { category: 'shopping', amount: 50 }, 
  { category: 'rent', amount: 1000 }, 
  { category: 'groceries', amount: 20 }, 
  { category: 'shopping', amount: 50 }
];

let result = data.reduce((acc, curr) => {
  let item = acc.find(item => item.category === curr.category);

  if (item) {
    item.amount += curr.amount;
  } else {
    acc.push(curr);
  }

  return acc;
}, []);

console.log(result);

Here is an alternative approach using object as the accumulator. This has a performance benefit as we wouldn't have to call find() on every iteration. Credits to frodo2975 for the suggestion.

const data = [
  { category: 'shopping', amount: 50 }, 
  { category: 'rent', amount: 1000 }, 
  { category: 'groceries', amount: 20 }, 
  { category: 'shopping', amount: 50 }
];

let result = Object.values(data.reduce((acc, curr) => {
  let item = acc[curr.category];

  if (item) {
    item.amount += curr.amount;
  } else {
    acc[curr.category] = curr;
  }

  return acc;
}, {}));

console.log(result);
like image 181
Nikhil Avatar answered Oct 25 '25 15:10

Nikhil


I would focus on efficiently computing the totals for each category, and then restructuring the data in the format that you need. So something like this:

// Construct an object mapping category to total amount.
const totals = data.reduce((totals, { category, amount }) => {
    totals[category] = (totals[category] || 0) + amount;
}, {});

// Format the data as you like.
const result = Object.entries(totals).map(([category, amount]) => ({ category, amount });
like image 36
kylepixel Avatar answered Oct 25 '25 16:10

kylepixel