Nested blocks in JS remapping function I have an array of objects that have a key attribute with the name of a country and a values attribute that is an array of values that contain data by year:



I needed the opposite: an array of objects where the key is the year and the values an array containing data for each country in the original array.



I wrote this script to remap it, but it feels like a huge hack to me. How can I do this in fewer lines of code and make it more readable?

self.dataByYear = []

$.each(self.dataByGroup, function(i,v) {
    $.each(v.values, function(j,x) {
        var inYears = self.dataByYear.filter(function(d) { return d.key == x.xgroup});
        if (inYears.length &gt; 0 )  {
            if (self.dataByYear[j] !== undefined) {
                self.dataByYear[j].values.push(x);
            }
        } else {
            newObj = {};
            newObj.key = x.xgroup;
            newObj.values = [x];
            self.dataByYear.push(newObj);
        }
    })
});
I'm not sure of any implementation that can actually trim this down (it's doomed to be at least 3 levels of loops), but here's an alternative approach in doing it which I think is much readable.

We group them by year first by going through each country, create an array for each year, and pushing them into the array. Then, we extract the key-value pairs and convert them into an array of objects containing key and value.

var yearsToCountries = self.dataByGroup.reduce(function(dataByYear, group){
  group.values.forEach(function(year){

    // If the country appears just once, then we can do this:
    (dataByYear[year] = dataByYear[year] || []).push(group.key);

    // If the country can appear more than once, we guard the push:
    dataByYear[year] = dataByYear[year] || [];
    if(!~dataByYear[year].indexOf(group.key)) dataByYear.push(group.key);

  });
  return dataByYear;
}, {});

// {
//   1990: ['US', 'Italy', ...],
//   1989: ['US', 'France', ...],
//   ...
// }

var dataByYears = Object.keys(yearsToCountries).map(function(year){
  return { key: year, values: yearsToCountries[year]};
});

// [
//   {key: '1990', values: ['US', 'Italy', ...]},
//   {key: '1989', values: ['US', 'France', ...]},
//   ...
// ]