Ryan Mortier
Ryan Mortier

Reputation: 883

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?

Upvotes: 0

Views: 59

Answers (1)

Erazihel
Erazihel

Reputation: 7605

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);

Upvotes: 3

Related Questions