简体   繁体   中英

Javascript ES6 calculate the sum of an array of arrays of objects

I have multiple arrays of objects with a string property "CountType" and a number property "ItemCount" .

The objects must be added up to calculate the total of all items by "CountType" property.

For example, I need to know the total number of Volumes, Sheets, Photos, etc.

Attempt #1: This code I attempted returns 0. Possibly that is because I need to loop through the outer array to do the comparison across the nested arrays.

function sumByProperty(items, prop) {
  if (items == null) {
      return 0;
  }
  return items.reduce(function (a, b) {
      return b[prop] == null ? a : a + b[prop];
  }, 0);
}

INPUT

Item count

[
    [
      {"CountType":"Volumes","ItemCount":3},
      {"CountType":"Sheets","ItemCount":6},
      {"CountType":"Photos","ItemCount":3},
      {"CountType":"Boxes","ItemCount":1},
      {"CountType":"Other","ItemCount":2}
    ],
    [
      {"CountType":"Volumes","ItemCount":1},
      {"CountType":"Sheets","ItemCount":1},
      {"CountType":"Photos","ItemCount":3},
      {"CountType":"Boxes","ItemCount":0},
      {"CountType":"Other","ItemCount":1}
    ],
    [
      {"CountType":"Volumes","ItemCount":1},
      {"CountType":"Sheets","ItemCount":0},
      {"CountType":"Photos","ItemCount":3},
      {"CountType":"Boxes","ItemCount":4},
      {"CountType":"Other","ItemCount":5}
    ]
]

DEISRED OUTPUT

Total count

[
  {"CountType":"Volumes","ItemCount":5},
  {"CountType":"Sheets","ItemCount":7},
  {"CountType":"Photos","ItemCount":9},
  {"CountType":"Boxes","ItemCount":5},
  {"CountType":"Other","ItemCount":8}
]

UPDATE: Here is how I am trying to run the function:

https://jsfiddle.net/yd051o76/2/

Possibly that is because I need to loop through the outer array to do the comparison across the nested arrays.

Indeed, you could flatten the array:

 function sumByProperty(items, prop) {
   return items.flat().reduce(function (a, b) {
     return b[prop] == null ? a : a + b[prop];
   }, 0);
 }

 const result = [
   { CountType: "Volumes", ItemCount: sumByProperty(input, "Volumes"), },
   //...
 ];

But I'd rather group dynamically using a hashtable, that way you only have to iterate once and you don't need to name all properties:

  const hash = new Map();

   for(const { CountType, ItemCount } of input.flat())
      hash.set(CountType, (hash.get(CountType) || 0) + ItemCount);

  const result = [...hash.entries()].map(([CountType, ItemCount]) => ({ CountType, ItemCount }));

Here's an example using 2 reduce functions with a for ... in ... to merge the results back into the parent reducer.

The trick is to make sure you initialize your accumulator as null so you can define your own. Then, it's just a matter of reducing the array of arrays and having another reducer to run the array of objects. Once done, you just need to merge the result of the inner array back into the parent. (Might be a better way to do this part)

Fiddle: https://jsfiddle.net/mswilson4040/jcp9x6ba/26/

 const json = [ [ {"CountType":"Volumes","ItemCount":3}, {"CountType":"Sheets","ItemCount":6}, {"CountType":"Photos","ItemCount":3}, {"CountType":"Boxes","ItemCount":1}, {"CountType":"Other","ItemCount":2} ], [ {"CountType":"Volumes","ItemCount":1}, {"CountType":"Sheets","ItemCount":1}, {"CountType":"Photos","ItemCount":3}, {"CountType":"Boxes","ItemCount":0}, {"CountType":"Other","ItemCount":1} ], [ {"CountType":"Volumes","ItemCount":1}, {"CountType":"Sheets","ItemCount":0}, {"CountType":"Photos","ItemCount":3}, {"CountType":"Boxes","ItemCount":4}, {"CountType":"Other","ItemCount":5} ] ]; const counts = json.reduce( (acc, currentArray) => { acc = acc ? acc : {}; const arrCounts = currentArray.reduce( (_acc, _item) => { _acc = _acc ? _acc : {}; _acc[_item.CountType] = _acc[_item.CountType] ? _acc[_item.CountType] + _item.ItemCount : _item.ItemCount; return _acc; }, null); for (const item in arrCounts) { acc[item] = acc[item] ? acc[item] + arrCounts[item] : arrCounts[item]; } return acc; }, null); console.log(counts); 

Try (data is input, h = {}, the r is result);

data.map(a=> a.map(x=> h[x.CountType]=x.ItemCount+(h[x.CountType]||0) ))

r= Object.keys(h).map(k=> ({CountType:k, ItemCount:h[k] }) );

 let data = [[ {"CountType":"Volumes","ItemCount":3}, {"CountType":"Sheets","ItemCount":6}, {"CountType":"Photos","ItemCount":3}, {"CountType":"Boxes","ItemCount":1}, {"CountType":"Other","ItemCount":2} ], [ {"CountType":"Volumes","ItemCount":1}, {"CountType":"Sheets","ItemCount":1}, {"CountType":"Photos","ItemCount":3}, {"CountType":"Boxes","ItemCount":0}, {"CountType":"Other","ItemCount":1} ], [ {"CountType":"Volumes","ItemCount":1}, {"CountType":"Sheets","ItemCount":0}, {"CountType":"Photos","ItemCount":3}, {"CountType":"Boxes","ItemCount":4}, {"CountType":"Other","ItemCount":5} ]]; let r,h = {}; data.map(a=> a.map(x=> h[x.CountType]=x.ItemCount+(h[x.CountType]||0) )) r= Object.keys(h).map(k=> ({CountType:k, ItemCount:h[k] }) ); console.log(r); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM