Conversion of data in javascript

Viewed 111

I have the following type of data assigned to var dataTransformation, which I'm taking from the user in apache superset using metric.

{country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779}
{country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492}
{country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195}
{country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865}
{country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722}
{country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502}
{country: "Canada", region: "North America", year: 1960, value: 30.939}
{country: "Canada", region: "North America", year: 1961, value: 30.332}
{country: "Canada", region: "North America", year: 1962, value: 29.506}

But I want to convert it into the below format. I tried it using the array map function, loops, and string concatenation but it is not efficient. Is there any way to do it in javascript?

{
   "South Asia": [
      ["Afghanistan", 91.779, 91.492, 91.195],
      ["Bangladesh", 94.865, 94.722, 94.502],
   ],
   "North America":[
      ["Canada", 30.939, 30.332, 29.506],
    ],
}

I'm expecting a guide on how to do it, not fully working code.

3 Answers

const data = [{
  country: "Afghanistan",
  region: "South Asia",
  year: 1960,
  value: 91.779
},{
  country: "Afghanistan",
  region: "South Asia",
  year: 1961,
  value: 91.492
},{
  country: "Afghanistan",
  region: "South Asia",
  year: 1962,
  value: 91.195
},{
  country: "Bangladesh",
  region: "South Asia",
  year: 1960,
  value: 94.865
},{
  country: "Bangladesh",
  region: "South Asia",
  year: 1961,
  value: 94.722
},{
  country: "Bangladesh",
  region: "South Asia",
  year: 1962,
  value: 94.502
},{
  country: "Canada",
  region: "North America",
  year: 1960,
  value: 30.939
},{
  country: "Canada",
  region: "North America",
  year: 1961,
  value: 30.332
},{
  country: "Canada",
  region: "North America",
  year: 1962,
  value: 29.506
}];

const res = data.reduce((acc, {country, region, year, value}) => {
  acc = {
    ...acc,
    [region]: {
      ...acc[region],
      [country]: !acc?.[region]?.[country] ? [value] : acc[region][country].concat(value) 
    }
  }
  return acc;
}, { });

console.log(res);

    const data = [
      { country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779 },
      { country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492 },
      { country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195 },
      { country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865 },
      { country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722 },
      { country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502 },
      { country: "Canada", region: "North America", year: 1960, value: 30.939 },
      { country: "Canada", region: "North America", year: 1961, value: 30.332 },
      { country: "Canada", region: "North America", year: 1962, value: 29.506 },
    ];


    const transformation = data.reduce((acc, curr) => {
      const { country, region, year, value } = curr;
      if (!acc[region]) {
        acc[region] = [];
        acc[region].push([country, value]);
        return acc;
      }

      let isCountryExist = false;

      acc[region].forEach((el) => {
        if (el.includes(country)) {
          isCountryExist = true;
          el.push(value);
        }
      });
      if (!isCountryExist) {
        acc[region].push([country, value]);
      }
      return acc;
    }, {});

    console.log(transformation);

Assuming that dataTransformation is an Array, the first step should be converting it to an object of regions containing objects with the countries as keys and arrays as values. This would keep the time complexity of this task at the minimum:

const dataTransformation = [
  {country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779},
  {country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492},
  {country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195},
  {country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865},
  {country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722},
  {country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502},
  {country: "Canada", region: "North America", year: 1960, value: 30.939},
  {country: "Canada", region: "North America", year: 1961, value: 30.332},
  {country: "Canada", region: "North America", year: 1962, value: 29.506}
];

const dataTransformationObject = dataTransformation.reduce((o, i) => {
  o[i.region] = o[i.region] || {};
  o[i.region][i.country] = o[i.region][i.country] || [];
  o[i.region][i.country].push(i.value);
  return o;
},{});

console.log(dataTransformationObject);

The previous code will return this object:

{
  "South Asia": {
    "Afghanistan": [
      91.779,
      91.492,
      91.195
    ],
    "Bangladesh": [
      94.865,
      94.722,
      94.502
    ]
  },
  "North America": {
    "Canada": [
      30.939,
      30.332,
      29.506
    ]
  }
}

And I strongly recommend you to use it directly in this way. Why? because to access to data > region > country, you can do it directly: e.g, data['North America']['Canada'][0] is 30.939. Otherwise you would need to iterate in the array of regions to find a country, and that would not be optimal.

But if you still need the output that you requested in your answer, you can transform the previous object to achieve it:

const dataTransformation = [
  {country: "Afghanistan", region: "South Asia", year: 1960, value: 91.779},
  {country: "Afghanistan", region: "South Asia", year: 1961, value: 91.492},
  {country: "Afghanistan", region: "South Asia", year: 1962, value: 91.195},
  {country: "Bangladesh", region: "South Asia", year: 1960, value: 94.865},
  {country: "Bangladesh", region: "South Asia", year: 1961, value: 94.722},
  {country: "Bangladesh", region: "South Asia", year: 1962, value: 94.502},
  {country: "Canada", region: "North America", year: 1960, value: 30.939},
  {country: "Canada", region: "North America", year: 1961, value: 30.332},
  {country: "Canada", region: "North America", year: 1962, value: 29.506}
];

const dataTransformationObject = dataTransformation.reduce((o, i) => {
  o[i.region] = o[i.region] || {};
  o[i.region][i.country] = o[i.region][i.country] || [];
  o[i.region][i.country].push(i.value);
  return o;
},{});

const final = Object.entries(dataTransformationObject).reduce((o, e) => {
  o[e[0]] = Object.keys(e[1]).map((c) => [c, ...e[1][c]]);
  return o;
}, {});

console.log(final);

Which will give you the desired output:

{
  "South Asia": [
    [
      "Afghanistan",
      91.779,
      91.492,
      91.195
    ],
    [
      "Bangladesh",
      94.865,
      94.722,
      94.502
    ]
  ],
  "North America": [
    [
      "Canada",
      30.939,
      30.332,
      29.506
    ]
  ]
}
Related