0

I have looked through stack overflow and feel like there is a much easier solution using map and reduce to solve this problem but this is my clumsy way to solve it so far. I need to sum up data by dates without having a "key" in the original json object. See below for the code snippet and result that seems to work. I would appreciate any input on doing this better. Thank you.

// input 
var array1 = [{'2019-07-13': 1, '2019-07-14': 4, '2019-07-15': 7}];
var array2 = [{'2019-07-13': 5, '2019-07-14': 8, '2019-07-15': 6}];
var array3 = [{'2019-07-13': 2, '2019-07-14': 1, '2019-07-15': 9}];

// output should look like this
// [{2019-07-13: 8, 2019-07-14: 13, 2019-07-15: 22}]

var combinedArray = [];
var finalArraySum = [];

// combine all the arrays into one...
var arrays = array1.concat(array2, array3);
arrays.forEach((array, index) => {
 Object.keys(array).forEach(function(key) {
  var element = [key, array[key]];
  combinedArray.push(element);
 })
});

// loop through the combined arrays
combinedArray.forEach((item, index) => {
 // figure out if the item already exists in the final summed up array
 var sumExists = finalArraySum.filter((innerItem, index) => {
  return innerItem[0] === item[0];
 });
 // if not exists, then push the initial one
 if(sumExists.length === 0) {
  finalArraySum.push([item[0], item[1]]);
 } else {
  // else add up to the already existing one
  sumExists[0][1] = item[1] + sumExists[0][1];
 }
})
console.log(finalArraySum);
var finalObject = [];
var stringObject = '{';
finalArraySum.forEach((item, index) => {
 console.log(item);
 stringObject = stringObject + '"' + item[0] + '":"' + item[1] + '",';
});
stringObject = stringObject.substr(0, stringObject.length - 1) + "}";
console.log(JSON.parse(stringObject));
finalObject.push(JSON.parse(stringObject));
console.log(finalObject);
user906573
  • 644
  • 1
  • 6
  • 22
  • Why are your input variables using objects wrapped in one-length arrays? – IronFlare Jul 10 '19 at 19:04
  • 4
    If the code is your own, it works, and you're looking for a complete review of the code, [codereview.se] might be a better match for this question. I strongly encourage you to read their [help center](https://codereview.stackexchange.com/help/how-to-ask) before asking though. – Heretic Monkey Jul 10 '19 at 19:07
  • You might also take a look at the answers to [Sum of array object property values in new array of objects in Javascript](https://stackoverflow.com/q/37481539/215552). – Heretic Monkey Jul 10 '19 at 19:09
  • Thank you so much for the feedback and answers. I will keep in mind the Code Review, which I was not aware of. @IronFlare, The reason why the inputs are formatted that way is simply the way I am getting the data from an API I do not have control over... – user906573 Jul 10 '19 at 20:15

3 Answers3

1

As @HereticMonkey notes, this question is probably better suited to the Code Review community, as StackOverflow is generally for getting help solving specific problems rather than for discussing the quality of functional code. Just keep that in mind for next time.

That being said, yes, it is possible to use Array#reduce here, but that's not the simplest way. Two loops and some destructuring are all you need.

var array1 = [{'2019-07-13': 1, '2019-07-14': 4, '2019-07-15': 7}];
var array2 = [{'2019-07-13': 5, '2019-07-14': 8, '2019-07-15': 6}];
var array3 = [{'2019-07-13': 2, '2019-07-14': 1, '2019-07-15': 9}];

let mergedInput = [...array1, ...array2, ...array3];

let temp = {};
for (a of mergedInput) {
 for (const [k, v] of Object.entries(a)) {
   temp[k] = (temp[k]||0)+a[k];
  }
}

console.log(temp);

If you're still interested in seeing an Array#reduce implementation, look in the revision history for my first answer.

IronFlare
  • 2,287
  • 2
  • 17
  • 27
  • Click on `<>` in editor can run it right here in stack snippet without having to go elsewhere – charlietfl Jul 10 '19 at 19:16
  • @charlietfl Okay, wow. I had no idea there was even a GUI for Stack Snippets. I'll definitely be leaning towards this from now on! – IronFlare Jul 10 '19 at 19:18
  • 1
    "not the simplest way" is my personal opinion of most uses of `reduce` that I see. – Barmar Jul 10 '19 at 19:26
1

You can accomplish this using Array.prototype.reduce -

const concat = (a = {}, b = {}) =>
  Object
    .entries(b)
    .reduce
      ( (r, [ k, v ]) =>
          ({ ...r, [k]: (r[k] || 0) + v })
      , a
      )

const main = (...all) =>
  all.reduce(concat, {})
  
var array1 =
  [{'2019-07-13': 1, '2019-07-14': 4, '2019-07-15': 7}]

var array2 =
  [{'2019-07-13': 5, '2019-07-14': 8, '2019-07-15': 6}]

var array3 =
  [{'2019-07-13': 2, '2019-07-14': 1, '2019-07-15': 9}]

console.log(main(...array1, ...array2, ...array3))
// { '2019-07-13': 8
// , '2019-07-14': 13
// , '2019-07-15': 22 
// }
Mulan
  • 129,518
  • 31
  • 228
  • 259
0

You can combine all the objects into the single array and reduce it as follows:

const array1 = [{'2019-07-13': 1, '2019-07-14': 4, '2019-07-15': 7}];
const array2 = [{'2019-07-13': 5, '2019-07-14': 8, '2019-07-15': 6}];
const array3 = [{'2019-07-13': 2, '2019-07-14': 1, '2019-07-15': 9}];

const all = [...array1, ...array2, ...array3];

const sumtotal = Object.keys(array1[0]).reduce((acc, key) => {
  return { ...acc, [key]: all.reduce((acc, arr) => acc + arr[key], 0) };
}, {});

console.log(sumtotal);
antonku
  • 7,377
  • 2
  • 15
  • 21