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

后端 未结 14 895
借酒劲吻你
借酒劲吻你 2020-12-29 03:32

I have an array of objects that looks like this:

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


        
相关标签:
14条回答
  • 2020-12-29 03:57

    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)

    0 讨论(0)
  • 2020-12-29 03:58

    Lodash

    Using lodash reduce and _.mergeWith this is a one liner:

    var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
    
    var result = _.reduce(data, (r,c) => _.mergeWith(r, c, (o = 0, s) => o + s), {})
    
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

    ES6 Only

    If you do NOT want to mutate the original array you can utilize ES6 reduce, Object.entries, and forEach like this:

    var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
    
    // One liner
    var result1 = data.reduce((r, c) =>
      !Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value) && r, {})
    
    // More readable
    var result2 = data.reduce((r, c) => {
      Object.entries(c).forEach(([key, value]) => r[key] = (r[key] || 0) + value)
      return r
    }, {})
    
    console.log(result1)
    console.log(result2)

    If we do not care about mutating the initial data array then we can have a one liner solution:

    var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
    
    data.reduce((r, c) => !Object.entries(c).forEach(([key,value]) => r[key] += value) && r)
    
    console.log(data[0])

    More readable:

    var data = [{costOfAirtickets: 2500, costOfHotel: 1200}, {costOfAirtickets: 1500, costOfHotel: 1000}]
    
    data.reduce((r, c) => {
      Object.entries(c).forEach(([key, value]) => r[key] += value)
      return r
    })
    
    console.log(data[0])

    The only difference between the mutating and not mutating examples is the initial value for the reduce (and also the fact that with the mutating we use the 0 index to as an accumulator for the sums). In the mutating ones there is no initial value where in the others we start with empty object literal.

    if you need the result to be an array specifically then return [data] for the mutating examples and [result] for the pure examples.

    0 讨论(0)
  • 2020-12-29 03:59

    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
    0 讨论(0)
  • 2020-12-29 04:00

    var data = [{costOfAirtickets: 2500, costOfHotel: 1200},{costOfAirtickets: 1500, costOfHotel: 1000}];
    
    var result = [data.reduce((acc, n) => {
      for (var prop in n) {
        if (acc[prop]) acc[prop] += n[prop];
        else acc[prop] = n[prop];
      }
      return acc;
    }, {})]
    console.log(result)

    0 讨论(0)
  • 2020-12-29 04:05

    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.

    0 讨论(0)
  • 2020-12-29 04:05

    My simplistic answer would be like;

    var data = [{costOfAirtickets: 2500, costOfHotel: 1200},
                {costOfAirtickets: 1500, costOfHotel: 1000}],
        res  = data.reduce((p,c) => Object.entries(c).reduce((r,[k,v]) => (r[k]+=v, r), p));
    console.log(res);

    A note on usage of .reduce(): If the array items and the accumulated value is of same type you may consider not using an initial value as an accumulator and do your reducing with previous (p) and current (c) elements. The outer reduce in the above snippet is of this type. However the inner reduce takes an array of key (k) value (v) pair as [k,v] to return an object, hence an initial value (p) is essential.

    The result is the accumulated value as an object. If you need it in an array then just put it in an array like [res].

    0 讨论(0)
提交回复
热议问题