简体   繁体   中英

array of objects group them by a specific key

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

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)

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);

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.

const result = [];
let yearData;
for (const {agrupacion, valor, year} of arr) {
  const colYear = `col${year}`;
  if (!yearData || colYear in yearData) {
    yearData = { agrupacion };
    result.push(yearData);
  }
  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 }; result.push(yearData); } 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 new yearData object is used if either agrupacion is different or col<year> is already present.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM