Logic to group data in array javascript

4

I'm having trouble grouping some data using JavaScript .

I have the following array of objects that return from the database and send it to view :

var object = [
    { data: 1, categories: "Branca", name: "Feminino" },
    { data: 1, categories: "Parda", name: "Masculino" },
    { data: 2, categories: "Branca", name: "Masculino" },
];

From it, I need to generate two more arrays grouped so I can send it to a chart in Highcharts .

I would like to get the following result:

categories: ["Parda", "Branca"]

series: [{
    name: "Masculino",
    data: [1, 2]
}, {
    name: "Feminino",
    data: [0, 1]
}]

I have already tested some possibilities, I did the array of categories , it was quite simple, but the array series > that complicated.

Can anyone help me? Thank you!

    
asked by anonymous 09.11.2018 / 00:59

2 answers

5

There are many ways to group, I'll choose to show one with reduce . Since your categories are linked to the values in data according to the positions the code ends up being a bit more complicated than it normally would be, but the logic is as follows:

  • Construct all categories that exist in the initial data
  • Scroll through each object in this data
  • If the object type (masc / fem) does not yet exist in the array then add a new entry
  • If already exists, only update the value of data
  • When you add, in the added object an array of data is added to all zeros with the same amount as the categories

Example:

const objects = [
    { data: 1, categories: "Branca", name: "Feminino" },
    { data: 1, categories: "Parda", name: "Masculino" },
    { data: 2, categories: "Branca", name: "Masculino" },
];

//construir primeiro todas as categorias existentes
const categories = [];
for (let obj of objects){ 
    if (!categories.includes(obj.categories)){
        categories.push(obj.categories);
    }
}

//agrupar os valores para as series com reduce
const series = objects.reduce((acc, val) => {
    let index = acc.map((o) => o.name).indexOf(val.name); //posicao do fem/masc
    let categoryIndex = categories.indexOf(val.categories); //posicao da categoria

    if (index === -1){ //se não existe 
        let newSeries = {
            name: val.name,
            data: new Array(categories.length).fill(0)
        }; //novo objeto para fem/masc já com um array de data todo a zeros
        
        //coloca o valor na posição correspondente à categoria
        newSeries.data[categoryIndex] = val.data; 
        acc.push(newSeries); //e adiciona o novo objeto à serie
    }
    else { 
        acc[index].data[categoryIndex] = val.data; //troca só o valor na data
    }

    return acc;
}, []); //inicia o reduce com array vazio

console.log(series, categories);

For the all-zero array creation I opted for the Array that receives the number of elements to create and subsequent method fill to fill in.

    
09.11.2018 / 01:52
2

var object = [
    { data: 1, categories: "Branca", name: "Feminino" },
    { data: 1, categories: "Parda", name: "Masculino" },
    { data: 2, categories: "Branca", name: "Masculino" },
];

var categories = [...new Set(object.map(a => a.categories))]

var series = [];
object.filter((thing, index, self) => index === self.findIndex((t) => (t.name === thing.name))).filter(arr => {
  var data = [];
  object.filter(obj => {
    if (obj.name === arr.name) {
      data.push(obj.data)
    }
  });
  series.push({
    name: arr.name,
    data: data
  });
});

var max = series.reduce((a, b) => Math.max(a.data.length, b.data.length));

series.filter(serie => {
  var newData = [];
  if (serie.data.length < max) {
    while (newData.length < (max - serie.data.length)) {
      newData.push(0);
    }
    newData = [...newData, ...serie.data];
  }
  if (newData.length > 0) {
    serie.data = newData;
  }
});


console.log(categories, series);
    
09.11.2018 / 01:59