Ryan Mortier Ryan Mortier - 3 years ago 99
Javascript Question

How do I go about "summarizing" an array of objects like this?

I have some data like this (simplified):

sales: [
{
'quantity': 20,
'amount': 40,
'product': {
'id': 1
'category': 'Chemical',
'subcategory': 'Herbicide'
}
},
{
'quantity': 10,
'amount': 70,
'product': {
'id': 1
'category': 'Chemical',
'subcategory': 'Herbicide'
}
},
{
'quantity': 30,
'amount': 60,
'product': {
'id': 2
'category': 'Seed',
'subcategory': 'Corn'
}
}
]


I want to group my data by the
product.id
and sum the
quantity
and
amount
and keep the same
category
and
subcategory
(which would be the same for all same product id's)

So basically I want my data to look like this:

filteredSum: [
{
'quantity': 30,
'amount': 110,
'product': {
'category': 'Chemical',
'subcategory': 'Herbicide'
}
},
{
'quantity': 30,
'amount': 60,
'product': {
'category': 'Seed',
'subcategory': 'Corn'
}
}
]


I'm using Lodash and this is what I came up with but something tells me there is a more succinct way of doing this?

filteredSum: function () {
return _(this.sales).groupBy('product.id').map(function (sales) {
return {
'quantity': _.sumBy(sales, function(sale) { return Number(sale.quantity); }).toFixed(2),
'amount': _.sumBy(sales, function(sale) { return Number(sale.amount); }),
'product': {
'category': _.head(sales).product.category,
'subcategory': _.head(sales).product.subcategory
}
}
}).value();
}


Surely there is a better way?

Answer Source

The easiest way is to have an Object with the productId as principal key. Then simply use a reduce to iterate over your array. If the productId of the current product already exists, simply sum its value to the previous one, otherwise add it to the object.

const data = [
  {
    'quantity': 20,
    'amount': 40,
    'product': {
      'id': 1,
      'category': 'Chemical',
      'subcategory': 'Herbicide'
    }
  },
  {
    'quantity': 10,
    'amount': 70,
    'product': {
      'id': 1,
      'category': 'Chemical',
      'subcategory': 'Herbicide'
    }
  },
  {
    'quantity': 30,
    'amount': 60,
    'product': {
      'id': 2,
      'category': 'Seed',
      'subcategory': 'Corn'
    }
  }
];

const result = data.reduce((acc, curr) => {
  if (acc[curr.product.id]) {
    acc[curr.product.id].quantity += curr.quantity;
    acc[curr.product.id].amount += curr.amount;
  } else {
    acc[curr.product.id] = curr;
  }
  
  return acc;
}, {});

const formatedResult = Object.keys(result).map(entry => {
  return result[entry];
});

console.log(formatedResult);

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download