Sum all data in array of objects into new array of objects

我只是一个虾纸丫 提交于 2019-12-03 10:45:42

问题


I have an array of objects that looks like this:

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}]

and I want to sum each element in the array to produce an array like this:

var result = [{costOfAirtickets: 4000, costOfHotel: 3200}]

I have used a map and reduce function but I was able to only sum an individual element like so:

data.map(item => ite.costOfAirtickets).reduce((prev, next)=>prev + next); // 22

At the moment this produces a single value which is not what I want as per initial explanation.

Is there a way to do this in Javascript or probably with lodash.


回答1:


Using for..in to iterate object and reduce to iterate array

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];

var result = [data.reduce((acc, n) => {
  for (var prop in n) {
    if (acc.hasOwnProperty(prop)) acc[prop] += n[prop];
    else acc[prop] = n[prop];
  }
  return acc;
}, {})]
console.log(result)



回答2:


Use Lodash to simplify your life.

const _ = require('lodash')
let keys = ['costOfAirtickets', 'costOfHotel']; 
let results = _.zipObject(keys, keys.map(key => _.sum( _.map(data, key))))
...
{ costOfAirtickets: 4000, costOfHotel: 2200 }

Explanation:

  • _.sum(_.map(data, key)): generates sum of each array
  • _.zipObject: zips the results with the array sum
  • using keys.map() for sum of each key as _.map does not guarantee order.

Documentation:

  • sum: https://lodash.com/docs/4.17.10#sum
  • zipObject: https://lodash.com/docs/4.17.10#zipObject
  • map: https://lodash.com/docs/4.17.10#map



回答3:


To create a resultant / reduced value, you should use .reduce() method instead of .map():

let data = [
  {costOfAirtickets: 2500, costOfHotel: 1200},
  {costOfAirtickets: 1500, costOfHotel: 1000}
];

let result = data.reduce(
  (a, c) => (Object.keys(c).forEach(k => (a[k] = (a[k] || 0) + c[k])), a), {}
);

console.log(result);



回答4:


Here is a lodash approach

_(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 1)).value()

It will sum by all the unique keys.

var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];

var res = _(data).flatMap(_.entries).groupBy(0).mapValues(v=>_.sumBy(v, 0)).value();

console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Wrap your result to a [...] or use a .castArray() at the end before unwrapping using .value() in case you want a array as result.




回答5:


You don't need to map the array, you're really just reducing things inside it.

const totalCostOfAirTickets: data.reduce((prev, next) => prev + next.costOfAirTickets, 0)
const totalCostOfHotel: data.reduce((prev, next) => prev + next.costOfHotel, 0)
const totals = [{totalCostOfAirTickets, totalCostOfHotel}]

In one go, you could do something like

const totals = data.reduce((prev, next) => { 
    prev.costOfAirTickets += next.costOfAirTickets; 
    prev.costOfHotel += next.costOfHotel; 
}, {costOfAirTickets: 0, costOfHotel: 0})



回答6:


Another solution would be to use Map (not Array.prototype.map) as it has several notable differences compared to objects:

var data = [{
  costOfAirtickets: 2500,
  costOfHotel: 1200
}, {
  costOfAirtickets: 1500,
  costOfHotel: 1000
}]

let sums = data.reduce((collection,rcd)=>{
  Object.entries(rcd).forEach(([key,value])=>{
      let sum = collection.get(key) || 0
      collection.set(key, sum + +value)
  })
  return collection
}, new Map())

console.log(...sums.entries())

Explanation

Outer loop

The above first iterates over your data array using the reduce method. Each object within that I'll be referring to as a record -- distinguished in the code via the variable, rcd.

Each iteration of reduce returns a value which is passed as the first argument to the next iteration of the loop. In this case, the parameter collection holds that argument, which is your set of sums.

Inner loop

Within the reduce loop, each key/value pair of the record is iterated over using forEach. To get the key/value pair the Object.entries method is used. Using array destructuring these arguments can be directly assigned to the respective variables, key and value

Retrieving/Setting values

Unlike a primitive object, Map has its own methods for getting and setting its entries using get() and set(). So first retrieve the previous sum using get(), if it's not set then default to 0, which is what the || 0 does. At that point, you can assume the previous sum is at least 0 or greater and add the current key's value onto it.

Alternatives to Map

If you find Map is a bit heavy-handed, you may also use a similar object such as Set, which has many of the same methods (except the get()), or you could also use a primitive object (i.e. {}).




回答7:


You could reduce the array by taking an object for summing.

var data = [{ costOfAirtickets: 2500, costOfHotel: 1200 }, { costOfAirtickets: 1500, costOfHotel: 1000 }],
    keys = ['costOfAirtickets', 'costOfHotel'],
    sum = data.reduce((r, o) => {
        keys.forEach(k => r[k] += o[k]);
        return r;
    }, Object.assign(...keys.map(k => ({ [k]: 0 }))));

console.log(sum);


来源:https://stackoverflow.com/questions/52479107/sum-all-data-in-array-of-objects-into-new-array-of-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!