I ended up developing a more generic function, presented below.
function group_by (lista, coluna) {
var colunas = {};
var resultado = [];
lista.forEach(function (item) {
var reg = {};
colunas[item[coluna]] = colunas[item[coluna]] || [];
for (var i in item)
if (i != coluna)
reg[i] = item[i];
colunas[item[coluna]].push(reg);
});
for (var i in colunas)
resultado.push({key: i, values: colunas[i]});
return resultado;
}
It naturally does groud by
on one level, returning a list of objects with the key
attributes, with the value of the selected column, and values
, with the remaining values.
Consider the entry below:
[
{
"disciplina": "Portugues",
"periodo": "1º Bimestre",
"tipo": "1ª avaliacao",
"valor": 9.5
},
{
"disciplina": "Matematica",
"periodo": "1º Bimestre",
"tipo": "1ª avaliacao",
"valor": 9.5
},
{
"disciplina": "Matematica",
"periodo": "1º Bimestre",
"tipo": "Trabalho",
"valor": 9.5
},
{
"disciplina": "Matematica",
"periodo": "2º Bimestre",
"tipo": "1ª avaliacao",
"valor": 6.3
}
]
Running group_by
on column periodo
, group_by(lista, "periodo")
, we would have the following output:
[
{
"key":"1º Bimestre",
"values":[
{
"disciplina":"Portugues",
"tipo":"1ª avaliacao",
"valor":9.5
},
{
"disciplina":"Matematica",
"tipo":"1ª avaliacao",
"valor":9.5
},
{
"disciplina":"Matematica",
"tipo":"Trabalho",
"valor":9.5
}
]
},
{
"key":"2º Bimestre",
"values":[
{
"disciplina":"Matematica",
"tipo":"1ª avaliacao",
"valor":6.3
}
]
}
]
To get a group by
of second degree, so to speak, just run the function on the list again in values
, in the desired column. For example, to now do group by
on the disciplina
column and get the expected result, we do:
group_by(lista, "periodo").map(function (item) {
return {key: item.key, values: group_by(item.values, "disciplina")};
});
Producing the following output:
[
{
"key":"1º Bimestre",
"values":[
{
"key":"Portugues",
"values":[
{
"tipo":"1ª avaliacao",
"valor":9.5
}
]
},
{
"key":"Matematica",
"values":[
{
"tipo":"1ª avaliacao",
"valor":9.5
},
{
"tipo":"Trabalho",
"valor":9.5
}
]
}
]
},
{
"key":"2º Bimestre",
"values":[
{
"key":"Matematica",
"values":[
{
"tipo":"1ª avaliacao",
"valor":6.3
}
]
}
]
}
]
How about testing for a larger ticket? Let's suppose that we want to separate the records according to tipo
, to separate notes of proofs, lists, etc.
group_by(lista, "periodo").map(function (item) {
return {key: item.key, values: group_by(item.values, "disciplina").map(function(item){
return {key: item.key, values: group_by(item.values, "tipo")}
})};
})
The output:
[
{
"key":"1º Bimestre",
"values":[
{
"key":"Portugues",
"values":[
{
"key":"Prova",
"values":[
{
"valor":9.5
}
]
},
{
"key":"Lista",
"values":[
{
"valor":8.8
},
{
"valor":5.2
}
]
}
]
},
{
"key":"Matematica",
"values":[
{
"key":"Prova",
"values":[
{
"valor":9.5
}
]
}
]
}
]
},
{
"key":"2º Bimestre",
"values":[
{
"key":"Biologia",
"values":[
{
"key":"Prova",
"values":[
{
"valor":9.5
}
]
},
{
"key":"Lista",
"values":[
{
"valor":10
}
]
}
]
}
]
},
{
"key":"3º Bimestre",
"values":[
{
"key":"Geografia",
"values":[
{
"key":"Lista",
"values":[
{
"valor":9.5
},
{
"valor":9.9
}
]
}
]
}
]
}
]