5

I have an array of js objects which look like this:

var objArr = [
     {"Country": "US", "City": "MyCity1", "2017-07-12": "1", "2017-07-13": "2"},
     {"Country": "US", "City": "MyCity2", "2017-07-12": "2", "2017-07-13": "2"},
     {"Country": "CN", "City": "MyCity1", "2017-07-12": "5", "2017-07-13": "7"},
     {"Country": "CN", "City": "MyCity2", "2017-07-12": "5", "2017-07-13": "7"}
   ]

I wanna create a new array where the country is unique, but also the dates should be summed.

{"Country": "US", "2017-07-12":  "3", "2017-07-13": "4"},
{"Country": "CN", "2017-07-12": "10", "2017-07-13": "14"}
            ^^^^                ^^^^                ^^^^   

I have problems getting my head around it. Do I have to filter first, reduce it somehow, remap it,... I've no idea to start? Any help would be appreciated, thank you!

Jan
  • 12,992
  • 9
  • 53
  • 89
  • Oh, in that case you just need to group the entries by country and then sum the values of the same properties – VLAZ Mar 02 '20 at 15:02
  • Does this answer your question? [Most efficient method to groupby on an array of objects](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects) – VLAZ Mar 02 '20 at 15:06
  • In particular, you can have a look at [Scott Sauyet's answer](https://stackoverflow.com/a/14484332/3689450) which provides a more flexible approach. Some others also show how you can group and transform. – VLAZ Mar 02 '20 at 15:08

3 Answers3

3

Use Array.reduce, check if an object with the current country exists, if it does, loop through the Object.keys to update the values, if not, push a new one :

EDIT : If you don't want City you can destructure it {City, ...curr}

var objArr = [
  { Country: "US", City: "MyCity1", "2017-07-12": "1", "2017-07-13": "2" },
  { Country: "US", City: "MyCity2", "2017-07-12": "2", "2017-07-13": "2" },
  { Country: "CN", City: "MyCity1", "2017-07-12": "5", "2017-07-13": "7" },
  { Country: "CN", City: "MyCity2", "2017-07-12": "5", "2017-07-13": "7" }
];

var result = objArr.reduce((acc, {City, ...curr}) => {
  const ndx = acc.findIndex(e => e.Country === curr.Country);
  if (ndx > -1) {
    const [country, ...keys] = Object.keys(curr);
    keys.forEach(k => {
      acc[ndx][k] = +acc[ndx][k] + +curr[k];
    });
  } else {
    acc.push(curr);
  }
  return acc;
}, []);

console.log(result);
Taki
  • 17,320
  • 4
  • 26
  • 47
0

You can use reduce() to create an object to group elements and then use Object.values

var objArr = [
     {"Country": "US", "City": "MyCity1", "2017-07-12": "1", "2017-07-13": "2"},
     {"Country": "US", "City": "MyCity2", "2017-07-12": "2", "2017-07-13": "2"},
     {"Country": "CN", "City": "MyCity1", "2017-07-12": "5", "2017-07-13": "7"},
     {"Country": "CN", "City": "MyCity2", "2017-07-12": "5", "2017-07-13": "7"}
   ]

let keys = ["2017-07-12", "2017-07-13"];
const res = Object.values(objArr.reduce((ac, a) => {
  if(!ac[a.Country]){
    ac[a.Country] = {Country: a.Country};
  }

  keys.forEach(k => {
    ac[a.Country][k] = (ac[a.Country][k] || 0) + Number(a[k]);
  })
  return ac;
}, {}))
console.log(res)
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
0

Use one forEach for array and go over each object date keys using forEach and build the one res object with unique keys as Country and accumulated values. Use Object.values of res to get the array from res object.

Update: Fix to make sure always one type for dates which is number.

var objArr = [
  { Country: "US", City: "MyCity1", "2017-07-12": "1", "2017-07-13": "2" },
  { Country: "US", City: "MyCity2", "2017-07-12": "2", "2017-07-13": "2" },
  { Country: "CN", City: "MyCity1", "2017-07-12": "5", "2017-07-13": "7" },
  { Country: "CN", City: "MyCity2", "2017-07-12": "5", "2017-07-13": "7" }
];

const update = data => {
  const res = {};
  data.forEach(({ Country, City, ...dates }) => {
    const item = res[Country] || { Country };
    Object.keys(dates).forEach(date => {
      item[date] = (item[date] || 0) + Number(dates[date]);
    });
    res[Country] = { ...item };
  });
  return Object.values(res);
};

console.log(update(objArr));
Siva K V
  • 10,561
  • 2
  • 16
  • 29
  • im some of my results the values are strings, and some are integers. Is this normal? ` Country: "China" 3/1/20: 79826 3/2/20: 80026 1: Country: "Thailand" 1/22/20: "2" 1/23/20: "3" – Jan Mar 03 '20 at 11:23
  • 1
    @Jan, Oh I see. I think its better to have same type for items. Here I think number is better. I updated answer to make sure always have number. – Siva K V Mar 03 '20 at 13:09