Search code examples
javascriptarrayssortingreduceremap

How to condense and remap data of array in Javascript


I have this array of data and need a remapped version of it to iterate through the dates.

var objArr = [
     {"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
     {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
     {"Country": "CN",  "2017-07-12": "5", "2017-07-13": "7"},
     {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
   ]
  • The countries should sum their values and should not appear twice in the inner array.
  • At the end I wanna have an array like this:
     var remapped = [
       {"2017-07-12": [
                    {"Country: "US", "value": 3}, 
                    {"Country: "CN", "value": 10}],
       {"2017-07-13": [
                    {"Country: "US", "value": 4},
                    {"Country: "US", "value": 14}]
     ]

In my current case, I get this, but countries should get reduced and the value summed:

var remapped = [
   {"2017-07-12": [
                {"Country: "US", "value": 1}, 
                {"Country: "US", "value": 2}, 
                {"Country: "CN", "value": 5}],
                {"Country: "CN", "value": 5}
                  ],
   {"2017-07-13": [
                {"Country: "US", "value": 2},
                {"Country: "US", "value": 2},
                {"Country: "US", "value": 7}
                {"Country: "US", "value": 7}
                 ]
 ]

This is what I've so far. But for me, it seems overcomplicated, and I am sure that there is a far more efficient way to solve that: At this state I have the countries remapped into the dates, but not sure how to "reduce" them. Do I really have to multiple iterates over the arrays?

const res = [];
dateArray.forEach(date => (objArr[date] = [])); // I create an array with dates which could contain another array

objArr.forEach(item => {
  dates.forEach(date => {
    res[date].push({
      Country: item['Country'],
      value: item[date],
    });
  });
});

Solution

  • You could do this using reduce method and first store values for each date in one object so you can group them by Country and then convert those objects to arrays.

    var data = [
     {"Country": "US", "2017-07-12": "1", "2017-07-13": "2"},
     {"Country": "US", "2017-07-12": "2", "2017-07-13": "2"},
     {"Country": "CN",  "2017-07-12": "5", "2017-07-13": "7"},
     {"Country": "CN", "2017-07-12": "5", "2017-07-13": "7"}
    ]
    
    const result = data.reduce((r, {Country, ...rest}, i) => {
      Object.entries(rest).forEach(([k, v]) => {
        if(!r[k]) r[k] = {}
        if(!r[k][Country]) r[k][Country] = {Country, value: +v}
        else r[k][Country].value += +v
      })
      
      return r;
    }, {})
    
    for(let i in result) {
      result[i] = Object.values(result[i])
    }
    
    console.log(result)