Home > Net >  array of objects group them by a specific key
array of objects group them by a specific key

Time:05-24

I have the following array

const arr = [{
  agrupacion: "Total país",
  valor: "81.8",
  year: 2015
}, {
  agrupacion: "Total país",
  valor: "86.4",
  year: 2016
}, {
  agrupacion: "Total país",
  valor: "67.3",
  year: 2017
}, {
  agrupacion: "Total país",
  valor: "70.8",
  year: 2018
}, {
  agrupacion: "Total país",
  valor: "67.6",
  year: 2019
}, {
  agrupacion: "Oriental",
  valor: "78.6",
  year: 2015
}, {
  agrupacion: "Oriental",
  valor: "83.1",
  year: 2016
}, {
  agrupacion: "Oriental",
  valor: "65.6",
  year: 2017
}, {
  agrupacion: "Oriental",
  valor: "68.1",
  year: 2018
}, {
  agrupacion: "Oriental",
  valor: "63.7",
  year: 2019
}, {
  agrupacion: "Occidental",
  valor: "177.3",
  year: 2015
}, {
  agrupacion: "Occidental",
  valor: "182.9",
  year: 2016
}, {
  agrupacion: "Occidental",
  valor: "114.3",
  year: 2017
}, {
  agrupacion: "Occidental",
  valor: "144.5",
  year: 2018
}, {
  agrupacion: "Occidental",
  valor: "169.9",
  year: 2019
}, {
  agrupacion: "Urbano",
  valor: "79.6",
  year: 2015
}, {
  agrupacion: "Urbano",
  valor: "92.5",
  year: 2016
}, {
  agrupacion: "Urbano",
  valor: "62.1",
  year: 2017
}, {
  agrupacion: "Urbano",
  valor: "82.2",
  year: 2018
}, {
  agrupacion: "Urbano",
  valor: "80.6",
  year: 2019
}, {
  agrupacion: "Rural",
  valor: "86.5",
  year: 2015
}, {
  agrupacion: "Rural",
  valor: "63.7",
  year: 2016
}, {
  agrupacion: "Rural",
  valor: "87.2",
  year: 2017
}, {
  agrupacion: "Rural",
  valor: "45.7",
  year: 2018
}, {
  agrupacion: "Rural",
  valor: "38.9",
  year: 2019
}];

I used this method to achieve what I wanted:

const groups = new Map(arr.map(({agrupacion}) => [agrupacion, { agrupacion }]));
for (const {agrupacion, valor, year} of arr) {
    groups.get(agrupacion)["col"   year] =  valor;
}

const result = [...groups.values()];

the output is (console.log(result )):

[{
  agrupacion: "Total país",
  col2015: 81.8,
  col2016: 86.4,
  col2017: 67.3,
  col2018: 70.8,
  col2019: 67.6
}, {
  agrupacion: "Oriental",
  col2015: 78.6,
  col2016: 83.1,
  col2017: 65.6,
  col2018: 68.1,
  col2019: 63.7
}, {
  agrupacion: "Occidental",
  col2015: 177.3,
  col2016: 182.9,
  col2017: 114.3,
  col2018: 144.5,
  col2019: 169.9
}, {
  agrupacion: "Urbano",
  col2015: 79.6,
  col2016: 92.5,
  col2017: 62.1,
  col2018: 82.2,
  col2019: 80.6
}, {
  agrupacion: "Rural",
  col2015: 86.5,
  col2016: 63.7,
  col2017: 87.2,
  col2018: 45.7,
  col2019: 38.9
}];

That output is the format I need however the problem comes when I add additional data with the same "agrupacion" value to my arr array, for example I add this at the end of my arr array

,{
  agrupacion: "Total país",
  valor: "151",
  year: 2015
}, {
  agrupacion: "Total país",
  valor: "184",
  year: 2016
}, {
  agrupacion: "Total país",
  valor: "165",
  year: 2017
}, {
  agrupacion: "Total país",
  valor: "147",
  year: 2018
}, {
  agrupacion: "Total país",
  valor: "190",
  year: 2019
}

This is what I need:

[{
  agrupacion: "Total país",
  col2015: 81.8,
  col2016: 86.4,
  col2017: 67.3,
  col2018: 70.8,
  col2019: 67.6
}, {
  agrupacion: "Oriental",
  col2015: 78.6,
  col2016: 83.1,
  col2017: 65.6,
  col2018: 68.1,
  col2019: 63.7
}, {
  agrupacion: "Occidental",
  col2015: 177.3,
  col2016: 182.9,
  col2017: 114.3,
  col2018: 144.5,
  col2019: 169.9
}, {
  agrupacion: "Urbano",
  col2015: 79.6,
  col2016: 92.5,
  col2017: 62.1,
  col2018: 82.2,
  col2019: 80.6
}, {
  agrupacion: "Rural",
  col2015: 86.5,
  col2016: 63.7,
  col2017: 87.2,
  col2018: 45.7,
  col2019: 38.9
},{
  agrupacion: "Total país",
  col2015: 151,
  col2016: 184,
  col2017: 165,
  col2018: 147,
  col2019: 190
}];

This is what I get with my attempt:

[{
  agrupacion: "Total país",
  col2015: 151,
  col2016: 184,
  col2017: 165,
  col2018: 147,
  col2019: 190
}, {
  agrupacion: "Oriental",
  col2015: 78.6,
  col2016: 83.1,
  col2017: 65.6,
  col2018: 68.1,
  col2019: 63.7
}, {
  agrupacion: "Occidental",
  col2015: 177.3,
  col2016: 182.9,
  col2017: 114.3,
  col2018: 144.5,
  col2019: 169.9
}, {
  agrupacion: "Urbano",
  col2015: 79.6,
  col2016: 92.5,
  col2017: 62.1,
  col2018: 82.2,
  col2019: 80.6
}, {
  agrupacion: "Rural",
  col2015: 86.5,
  col2016: 63.7,
  col2017: 87.2,
  col2018: 45.7,
  col2019: 38.9
}]

Apparently it overwrites all the values from the first "Total país" rather than repeating that agrupacion with the new values that I added

CodePudding user response:

Try this forEach function :

 let arrayBuild = []
      let results = []
      let currentAgrupacion = ''
      let element = {}
      
      arr.forEach(elem => {
        if(currentAgrupacion !== elem.agrupacion) {
          if(currentAgrupacion !== '') {
            results.push(element)
          }
          currentAgrupacion = elem.agrupacion
          element = {
            agrupacion: elem.agrupacion
          }
      element["col" elem.year] = parseFloat(elem.valor)
    }
    else {
      element["col" elem.year] = parseFloat(elem.valor)
    }
  })
  results.push(element)

  console.log(results)

CodePudding user response:

Reduce the array into an object where the keys correspond to the agrupacion and the values correspond to an array of objects. And the length of this array is decided based on how many times an year appears for a particular agrupacion.

So, the following array:

[
  { agrupacion: "Total país", valor: "81.8", year: 2015 },
  { agrupacion: "Total país", valor: "86.4", year: 2016 },
  { agrupacion: "Total país", valor: "67.3", year: 2015 },
  { agrupacion: "Oriental", valor: "78.6", year: 2015 },
]

Is reduced into the following object:

{
  "Total país": [
    { agrupacion: "Total país", col2015: 81.8, col2016: 86.4 },
    { agrupacion: "Total país", col2015: 67.3 },
  ],
  Oriental: [{ agrupacion: "Oriental", col2015: 78.6 }],
}

And finally we get the values of this object and flatten it to the desired result.

const arr = [
  { agrupacion: "Total país", valor: "81.8", year: 2015 },
  { agrupacion: "Total país", valor: "86.4", year: 2016 },
  { agrupacion: "Total país", valor: "67.3", year: 2017 },
  { agrupacion: "Total país", valor: "70.8", year: 2018 },
  { agrupacion: "Total país", valor: "67.6", year: 2019 },
  { agrupacion: "Oriental", valor: "78.6", year: 2015 },
  { agrupacion: "Oriental", valor: "83.1", year: 2016 },
  { agrupacion: "Oriental", valor: "65.6", year: 2017 },
  { agrupacion: "Oriental", valor: "68.1", year: 2018 },
  { agrupacion: "Oriental", valor: "63.7", year: 2019 },
  { agrupacion: "Occidental", valor: "177.3", year: 2015 },
  { agrupacion: "Occidental", valor: "182.9", year: 2016 },
  { agrupacion: "Occidental", valor: "114.3", year: 2017 },
  { agrupacion: "Occidental", valor: "144.5", year: 2018 },
  { agrupacion: "Occidental", valor: "169.9", year: 2019 },
  { agrupacion: "Urbano", valor: "79.6", year: 2015 },
  { agrupacion: "Urbano", valor: "92.5", year: 2016 },
  { agrupacion: "Urbano", valor: "62.1", year: 2017 },
  { agrupacion: "Urbano", valor: "82.2", year: 2018 },
  { agrupacion: "Urbano", valor: "80.6", year: 2019 },
  { agrupacion: "Rural", valor: "86.5", year: 2015 },
  { agrupacion: "Rural", valor: "63.7", year: 2016 },
  { agrupacion: "Rural", valor: "87.2", year: 2017 },
  { agrupacion: "Rural", valor: "45.7", year: 2018 },
  { agrupacion: "Rural", valor: "38.9", year: 2019 },
  { agrupacion: "Total país", valor: "151", year: 2015 },
  { agrupacion: "Total país", valor: "184", year: 2016 },
  { agrupacion: "Total país", valor: "165", year: 2017 },
  { agrupacion: "Total país", valor: "147", year: 2018 },
  { agrupacion: "Total país", valor: "190", year: 2019 },
];

const result = Object.values(
  arr.reduce((r, o) => {
    if (!r[o.agrupacion]) {
      r[o.agrupacion] = [{ agrupacion: o.agrupacion }];
    }
    const item = r[o.agrupacion].find((i) => !i["col"   o.year]);
    if (item) {
      item["col"   o.year] = parseFloat(o.valor);
    } else {
      r[o.agrupacion].push({
        agrupacion: o.agrupacion,
        ["col"   o.year]: parseFloat(o.valor),
      });
    }
    return r;
  }, {})
).flat();

console.log(result);

CodePudding user response:

You could keep track of the last yearData (the group of data you're collecting). If a given col<year> is already present within this object, create a new object. If it's not present, add it to the current object.

const result = [];
let yearData;
for (const {agrupacion, valor, year} of arr) {
  const colYear = `col${year}`;
  if (!yearData || colYear in yearData) {
    yearData = { agrupacion, [colYear]:  valor };
    result.push(yearData);
  } else {
    yearData[colYear] =  valor;
  }
}

const arr = [
  { agrupacion: "Total país", valor: "81.8",  year: 2015 },
  { agrupacion: "Total país", valor: "86.4",  year: 2016 },
  { agrupacion: "Total país", valor: "67.3",  year: 2017 },
  { agrupacion: "Total país", valor: "70.8",  year: 2018 },
  { agrupacion: "Total país", valor: "67.6",  year: 2019 },
  { agrupacion: "Oriental",   valor: "78.6",  year: 2015 },
  { agrupacion: "Oriental",   valor: "83.1",  year: 2016 },
  { agrupacion: "Oriental",   valor: "65.6",  year: 2017 },
  { agrupacion: "Oriental",   valor: "68.1",  year: 2018 },
  { agrupacion: "Oriental",   valor: "63.7",  year: 2019 },
  { agrupacion: "Occidental", valor: "177.3", year: 2015 },
  { agrupacion: "Occidental", valor: "182.9", year: 2016 },
  { agrupacion: "Occidental", valor: "114.3", year: 2017 },
  { agrupacion: "Occidental", valor: "144.5", year: 2018 },
  { agrupacion: "Occidental", valor: "169.9", year: 2019 },
  { agrupacion: "Urbano",     valor: "79.6",  year: 2015 },
  { agrupacion: "Urbano",     valor: "92.5",  year: 2016 },
  { agrupacion: "Urbano",     valor: "62.1",  year: 2017 },
  { agrupacion: "Urbano",     valor: "82.2",  year: 2018 },
  { agrupacion: "Urbano",     valor: "80.6",  year: 2019 },
  { agrupacion: "Rural",      valor: "86.5",  year: 2015 },
  { agrupacion: "Rural",      valor: "63.7",  year: 2016 },
  { agrupacion: "Rural",      valor: "87.2",  year: 2017 },
  { agrupacion: "Rural",      valor: "45.7",  year: 2018 },
  { agrupacion: "Rural",      valor: "38.9",  year: 2019 },
  { agrupacion: "Total país", valor: "151",   year: 2015 },
  { agrupacion: "Total país", valor: "184",   year: 2016 },
  { agrupacion: "Total país", valor: "165",   year: 2017 },
  { agrupacion: "Total país", valor: "147",   year: 2018 },
  { agrupacion: "Total país", valor: "190",   year: 2019 },
];

const result = [];
let yearData;
for (const { agrupacion, valor, year } of arr) {
  const colYear = `col${year}`;
  if (!yearData || colYear in yearData) {
    yearData = { agrupacion, [colYear]:  valor };
    result.push(yearData);
  } else {
    yearData[colYear] =  valor;
  }
}

console.log(result);

The answer does assume a certain consistency in arr. Namely that each group of items share the exact same year range (2015-2019 in your data), and there are no missing years.

An example of an inconsistent input that produces a wrong output is:

const arr = [
  { agrupacion: "a", valor: "1", year: 2015 },
  { agrupacion: "a", valor: "2", year: 2016 },
  { agrupacion: "a", valor: "3", year: 2017 },
  { agrupacion: "b", valor: "4", year: 2015 },
  // 2016 missing
  { agrupacion: "b", valor: "5", year: 2017 },
  // 2015 missing
  { agrupacion: "c", valor: "6", year: 2016 },
  { agrupacion: "c", valor: "7", year: 2017 },
];

Which results in:

[
  { agrupacion: "a", col2015: 1, col2016: 2, col2017: 3 },
  { agrupacion: "b", col2015: 4, col2016: 6, col2017: 5 },
  { agrupacion: "c",                         col2017: 7 },
]

If these gaps in data can occur you'll want to change:

if (!yearData || colYear in yearData)

Into:

if (!yearData || agrupacion != yearData.agrupacion || colYear in yearData)

To ensure that a col<year> value is only written if the agrupacion is the same.

  • Related