0

I have the following array:

var array = []
array.push({payslipId: 1759});
array.push({payDate: "2019-04-19T00:00:00+00:00"});
array.push({periodsPerYear: 52});
array.push({taxPeriod: 2});
array.push({payslipId: 1760});
array.push({payDate: "2019-04-19T00:00:00+00:00"});
array.push({periodsPerYear: 52});
array.push({taxPeriod: 2});

What I am hoping to be able to do is create an array of distinct names, and where the values are numeric, the total off all in the above array would be shown.

The only way I can think to do this is to create a new array, and add each name to it, then loop around the above array, and add to the value to the name, if the value is numeric.

I am not overly familiar with javascript, so am hoping there is a neater way, a bit like linq in C#?

Desired output:

[{ payslipId: 3519 }, { periodsPerYear: 104} , { taxPeriod: 4}]

Keith
  • 1,008
  • 10
  • 19
  • Possible duplicate of [Group by in Javascript using reduce](https://stackoverflow.com/questions/51040651/group-by-in-javascript-using-reduce) – PM 77-1 Aug 29 '19 at 18:12
  • The array has four different key-value pairs: `payslipId`, `payDate`, 'periodsPerYear` and `taxPeriod`. When you say you want to add up numeric values do you mean all fields except `payDate`? Why do wan to add `payslipId` with `period` related fields? – fiveelements Aug 29 '19 at 18:13
  • 1
    Can you show how your desired output looks like ? IMO you're looking for `Object` – Code Maniac Aug 29 '19 at 18:14
  • Added the desired output to the question. – Keith Aug 29 '19 at 18:17
  • @PM77-1 hmm, I ideally don't want to have to tell a function what the fields are, I'd like to group it, as the array can be different, and I want a generic function. – Keith Aug 29 '19 at 18:27
  • Use `reduce()` function to aggregate – fiveelements Aug 29 '19 at 18:42
  • @Leonidas199x are you interested with the 3 objects only? – Addis Aug 29 '19 at 18:49
  • A similar question here: https://stackoverflow.com/q/52720034/4636715 – vahdet Aug 29 '19 at 19:11

3 Answers3

1

As I have mentioned in the comment to the original post, you can use reduce() function for aggregation. You may apply any condition you need to for aggregation. As you have mentioned, I have considered number fields only.

Here you go:

var array = []
array.push({ payslipId: 1759 });
array.push({ payDate: "2019-04-19T00:00:00+00:00" });
array.push({ periodsPerYear: 52 });
array.push({ taxPeriod: 2 });
array.push({ payslipId: 1760 });
array.push({ payDate: "2019-04-19T00:00:00+00:00" });
array.push({ periodsPerYear: 52 });
array.push({ taxPeriod: 2 });

//console.log(array);
result = array.reduce((aggr, item) => {
    itemKey = Object.keys(item)[0];
    if (Number.isInteger(item[itemKey])) {
        if (!aggr[itemKey]) {
            aggr[itemKey] = 0;
        }
        aggr[itemKey] = parseInt(aggr[itemKey]) + parseInt(item[itemKey]);
    }
    return aggr;
}, {});
console.log(result);
fiveelements
  • 3,649
  • 1
  • 17
  • 16
1

You could take a Map and reduce the array by taking the only key/value pair of the object.

function group(array) {
    return Array.from(
        array.reduce((m, o) => {
            var [k, v] = Object.entries(o)[0];
            return typeof v === 'number'
                ? m.set(k, (m.get(k) || 0) + v)
                : m;
        }, new Map),
        ([k, v]) => ({ [k]: v })
    );
}

var array = [{ payslipId: 1759 }, { payDate: "2019-04-19T00:00:00+00:00" }, { periodsPerYear: 52 }, { taxPeriod: 2 }, { payslipId: 1760 }, { payDate: "2019-04-19T00:00:00+00:00" }, { periodsPerYear: 52 }, { taxPeriod: 2 }],
    result = group(array);

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Another option could be:

let array2 = [array[0]];
array.shift();

array.forEach(obj => {
  if(typeof(obj[Object.keys(obj)[0]]) !== 'number')  return;
  //test if the object with the same property name already exists to array2 or not. If it doesn't exist, it will be added to array2. If it does only the value will be added to the existing element
  let test = array2.reduce((accum,obj2) => {
    return accum && (Object.keys(obj2)[0] !== Object.keys(obj)[0]);
  }, true);
  if(test)     array2.push(obj);
  else  array2.find(obj2 => obj2.hasOwnProperty(Object.keys(obj)[0]))[Object.keys(obj)[0]] += obj[Object.keys(obj)[0]];
});

console.log(array2);
Addis
  • 2,480
  • 2
  • 13
  • 21