Logic for grouping data in javascript array

Asked

Viewed 1,771 times

5

I’m having trouble grouping some data using the Javascript.

I have the following array of objects that return from database and shipping to the 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, to send to a chart on Highcharts.

I would like to arrive at the following result:

categories: ["Parda", "Branca"]

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

I’ve tried some possibilities, I’ve done the array of Categories, was very simple, but the array of series that complicated.

Could someone help me? Thanks in advance!

  • Why does Feminine need to have the dates 0 and 1? What is the logic of the dates?

  • The logic of the dates follows the order of the categories. Ex: Looking through the original array, the masculine when Parda, has the date 1, and when White the date 2. Whereas the Feminine has no value when Parda, so its date is 0, and has when White the date 1.

  • You can take a look at this link that might help you: Groupby And I think this post I found might help a lot: https://stackoverflow.com/questions/21776389/javascript-object-grouping

2 answers

6


There are many ways to group, I will choose to show one with reduce. How your categories are linked to values in data according to the positions the code turns out to be a little more complicated than it would normally be, but the logic is as follows:

  • Find all categories 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 adds a new entry
  • If it already exists only updates the value of data
  • When you add, the added object creates an array of data all zeroes of the same quantity as 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 creation of the whole array I opted for the constructor of Array which receives the amount of elements to be created and the subsequent method fill to fill in.

  • I tested your solution with more objects in the array and different shapes, it works perfectly. I studied your code for understanding, and liked it very much. Thank you very much!

  • @Taciiobrito No problem, we’re here to help :)

4

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.