Agrupar listas com Object.groupBy
O Object.groupBy entrou no JavaScript com o ECMAScript 2024 e resolve uma coisa que toda a gente já escreveu à mão pelo menos uma vez: separar uma lista em grupos, segundo um critério qualquer.
O que muda
Deixa de ser preciso um
reducecom um acumulador e a verificação do costume para o caso de a chave ainda não existir.O objeto devolvido não tem protótipo — não herda
toStringnem nada — portanto uma chave chamadaconstructornão estraga nada.As chaves são sempre texto. Quem precisar de agrupar por objetos ou por números a sério tem o
Map.groupBy, que devolve umMap.
1. O antes e o depois
const despesas = [
{ descricao: 'Alojamento', valor: 120, categoria: 'viagem' },
{ descricao: 'Almoço', valor: 14, categoria: 'comida' },
{ descricao: 'Comboio', valor: 32, categoria: 'viagem' },
{ descricao: 'Café', valor: 2, categoria: 'comida' },
];
// Antes: acumulador, verificação, e a chave criada à mão
const antes = despesas.reduce((grupos, despesa) => {
grupos[despesa.categoria] ??= [];
grupos[despesa.categoria].push(despesa);
return grupos;
}, {});
// Depois
const porCategoria = Object.groupBy(despesas, (despesa) => despesa.categoria);
console.log(porCategoria.viagem.length); // 22. Agrupar por um critério calculado
A função recebe também o índice, e o que ela devolver é a chave. Não tem de ser um campo do objeto:
const porPreco = Object.groupBy(despesas, (despesa) =>
despesa.valor > 30 ? 'caras' : 'baratas'
);
console.log(Object.keys(porPreco)); // [ 'caras', 'baratas' ]3. Quando a chave não é texto
const lisboa = { nome: 'Lisboa' };
const funchal = { nome: 'Funchal' };
const registos = [
{ destino: lisboa, dias: 3 },
{ destino: funchal, dias: 10 },
{ destino: lisboa, dias: 1 },
];
// Com Object.groupBy, ambos os destinos viravam a chave "[object Object]"
const porDestino = Map.groupBy(registos, (registo) => registo.destino);
console.log(porDestino.get(lisboa).length); // 2Está nos browsers desde 2024 e no Node a partir da versão 21. Em código que tenha de correr em sítios mais antigos, o reduce de sempre continua a servir.