Como Agregar Dados de Forma Eficiente em JavaScript - Dominando o reduce()
đIntrodução
Durante o desenvolvimento de software, muitas vezes precisamos agregar relatĂłrios đ que resumem e estruturam dados de forma clara. Isso facilita tanto o entendimento do usuĂĄrio quanto a tomada de decisĂ”es đ€.
const clientes = [
{nome: 'Ana', idade: 25, cidade: 'SĂŁo Paulo', sexo: 'F'},
{nome: 'Fernando', idade: 44, cidade: 'SĂŁo Francisco do Conde', sexo: 'M'},
{nome: 'JoĂŁo', idade: 19, cidade: 'SĂŁo Chapadinha', sexo: 'M'},
{nome: 'Bernardo', idade: 31, cidade: 'BrasĂlia', sexo: 'M'},
{nome: 'JĂșlia', idade: 27, cidade: 'Rio de Janeiro', sexo: 'F'},
]
Se o usuĂĄrio precisar entender quantos clientes existem em cada cidade ou qual a distribuição por gĂȘnero, ele terĂĄ dificuldades ao analisar os dados dessa forma.
Felizmente, com o mĂ©todo reduce(), podemos transformar essa estrutura de dados em um formato mais organizado e legĂvel, facilitando sua anĂĄlise.Â
đO que faz o mĂ©todo reduce()?
O mĂ©todo reduce() Ă© uma função de alta ordem em JavaScript que permite percorrer um array e acumular seus valores de acordo com uma lĂłgica definida pelo programador. Seu principal objetivo Ă© reduzir um conjunto de dados a um Ășnico valor ou estrutura, que pode ser um nĂșmero, string, array ou objeto.
No exemplo mencionado na introdução, queremos agrupar os clientes por gĂȘnero. Para isso, podemos utilizar reduce() para transformar a lista de clientes em um objeto que contĂ©m a contagem de pessoas do gĂȘnero masculino e feminino, ignorando outras informaçÔes como nome, idade e cidade.
O resultado esperado seria:
{clientePorGenero: {masculino: 3, feminino: 2}}
đ§âđComo aprendi o mĂ©todo?
Ao iniciar no desenvolvimento, percebi que entender lógica de programação e estrutura de dados era fundamental, especialmente para lidar com respostas vindas do banco de dados e retornos de métodos que envolvem diferentes formatos de dados.
Foi então que decidi usar a IA ChatGPT para me ajudar a melhorar nesse aspecto, começando pelos arrays. Durante a conversa, a IA me desafiou a somar os itens de um array e, instintivamente, tentei usar forEach(). Foi nesse momento que recebi a sugestão de usar reduce(), um método que eu ainda não dominava.
A partir daĂ, fui recebendo desafios progressivamente mais complexos, simulando problemas do dia a dia de um desenvolvedor. Com cada exercĂcio, fui compreendendo melhor a utilidade do reduce() e sua aplicação prĂĄtica em problemas reais.
seuArray.reduce((acumulador, valorAtual, Ăndice, arrayOriginal) => {
// Lógica de acumulação
}, valorInicial)
O reduce() sempre retorna um valor, que pode ser um nĂșmero, string, objeto ou atĂ© mesmo um array. Esse retorno precisa ser armazenado para ser utilizado posteriormente.
đ€Quais argumentos o reduce() recebe?
Acumulador: O valor que é atualizado a cada iteração.
Valor atual: O item atual do array sendo processado.
Ăndice (opcional): A posição do item dentro do array.
Array original (opcional): O array completo sobre o qual o reduce() estĂĄ sendo executado.
Valor inicial (opcional): Define o valor inicial do acumulador. Se nĂŁo for informado, o primeiro item do array serĂĄ usado como valor inicial.
O valor inicial Ă© importante porque determina o formato da saĂda. Se for um objeto {}, o resultado serĂĄ um objeto; se for um array [], o retorno serĂĄ um array; se for 0, o resultado serĂĄ um nĂșmero acumulado.
O reduce() Ă© especialmente Ăștil para resumir e transformar dados, como no caso de um array de objetos, onde ele pode agregar informaçÔes de forma estruturada.
đSintaxe bĂĄsica
A sintaxe bĂĄsica do reduce envolve sempre a presença de um acumulador e um valor atual, importante para evitar bugs a inicialização do acumulador para evitar retornos inesperados.Â
let max = [0, 1, 2, 3, 4, 5].deduce(function(acc, valorAtual){
if(acc > valorAtual) {acc = acc}
else{acc = valorAtual}
return acc
}, 0)
đExplicação:
-  A função de callback recebe dois parùmetros:
- acc (acumulador): Armazena o maior valor encontrado até o momento;
- valorAtual: O nĂșmero atual do array que estĂĄ sendo analisado.
- A cada iteração, o código verifica se acc é maior que valorAtual:
- Se for, acc mantém seu valor.
- Caso contrĂĄrio, acc assume o valor de valorAtual.
- Ao final, reduce() retorna o maior valor encontrado, que serĂĄ armazenado na variĂĄvel max.ParĂąmetros (accumulator, currentValue, index, array)
Neste exemplo, que apenas muda a função de call-back, no exemplo anterior apenas compara os valores entre o acc e o valorAtual, neste exemplo, adiciona ao acc, que estå inicializado com 0, o valorAtual, gerando uma soma a cada iteração.
Uma aplicação pråtica para esta soma usando reduce seria calcular o total de vendas em um sistema de e-commerce.
Imagine que vocĂȘ tenha um array apresentando compras realizadas, onde cada item tem um valor:
const vendas = [100, 250, 75, 300, 150];
const totalVendas = vendas.reduce((acc, valorAtual) => acc + valorAtual, 0)
console.log(`Total de vendas: R$ ${totalVendas}`)
//saĂda: Total de vendas R$ 875
đExplicação:
- O acumulador (acc) começa com 0;
- A cada iteração valorAtual (o valor de uma venda) é somado ao acc;
- No final, reduce() retorna a soma total das vendas, que pode ser exibida para um administrador da loja.
Observação importante: Esse mesmo conceito pode ser aplicado para calcular despesas, notas de alunos, pontos de um jogo.
đReduce() na PrĂĄtica: Agregando dados Complexos
Ă possĂvel realizar agrupamentos de dados em um objeto por uma de suas propriedades. Veja o exemplo que segue:
let pessoas = [
{ nome: âRosanaâ, idade: 20},
{ nome: âMaxâ, idade: 22},
{ nome: âJaneâ, idade: 20},
]
function agruparPor(objetoArray, propriedade){
return objetoArray.reduce((acc, obj) => {
let key = obj[propriedade];
if(!acc[key]){acc[key] = [];}
acc[key].push(obj);
return acc;
}, {});
}
let grupoDePessoas = agruparPor(pessoas, âidadeâ)
//SaĂda
//grupoPessoas Ă©:
//{
// 20: [
// {nome: âRosanaâ, idade: 20},
// {nome: âJaneâ, idade: 20},
// ],
// 22:[{nome: âMaxâ, idade: 22}]
//}
đ€ŻIntrodução de um problema realÂ
Somando Faturamento Mensal đ
Imagine que vocĂȘ trabalha para uma empresa que quer analisar seu faturamento mensal. EntĂŁo vocĂȘ deve somar o total de faturamento para cada mĂȘs e apresentar o resumo.
const transaçÔes = [
{mes: âJaneiroâ, valor: 1000},
{mes: âFevereiroâ, valor: 1500},
{mes: âJaneiroâ, valor: 500},
{mes: âMarçoâ, valor: 2000},
{mes: âFevereiroâ, valor: 1000},
];
function relatorioFaturamento(transacoes){
return transaçÔes.reduce((acc, transacao) => {
const { mes, valor } = transação
acc[mes] = acc[mes] ? acc[mes] + valor : valor;
return acc;
}, {});
}
console.log(relatoriaFaturamento(transaçÔes))
// SaĂda: { Janeiro: 1500, Fevereiro: 2500, Março: 2000 }
Contar FrequĂȘncia de Clientes đ
Imagina que vocĂȘ quer saber qual Ă© o cliente mais frequente de teu e-commerce. VocĂȘ tem um array com as compras realizadas:
const compras = [
{id: 101, cliente: âMaria Aparecidaâ, email: âmaria.aparecida@email.comâ},
{id: 202, cliente: âPaulo Augustoâ, email: âaugustos@email.comâ},
{id: 101, cliente: âMaria Aparecidaâ, email: âmaria.aparecida@email.comâ},
{id: 303, cliente: âRaissa Louretoâ, email: âlouretinho@email.comâ},
{id: 202, cliente: âPaulo Augustoâ, email: âaugustos@email.comâ},
{id: 101, cliente: âMaria Aparecidaâ, email: âmaria.aparecida@email.comâ},
{id: 404, cliente: âJosĂ© Pauloâ, email: âpaulo.jose@email.comâ},
{id: 404, cliente: âJosĂ© Pauloâ, email: âpaulo.jose@email.comâ},
{id: 404, cliente: âJosĂ© Pauloâ, email: âpaulo.jose@email.comâ},
{id: 202, cliente: âPaulo Augustoâ, email: âaugustos@email.comâ},
{id: 202, cliente: âPaulo Augustoâ, email: âaugustos@email.comâ},
]
function relatorioVendas(arr) {
return arr.reduce((acc, { id, cliente }) => {
acc[cliente] = (acc[cliente] || 0) + 1
return acc
}, {})
}
console.log(relatorioVendas(compras))
// SaĂda:
{ 'Maria Aparecida': 3,
'Paulo Augusto': 4,
'Raissa Loureto': 1,
'José Paulo': 3 }
Para os casos apresentados, o reduce Ă© muito vantajoso.
No exemplo do faturamento mensal o uso do reduce Ă© extremante eficiente, e se comparar com o uso de forEach() + if().
No que se trata da frequĂȘncia de compra pelos clientes o mĂ©todo reduce evita a necessidade de criar objeto auxiliar antes de percorrer os dados.
Boas PrĂĄticas e Armadilhas Comuns ao Usar reduce()đ ïžsim
O mĂ©todo reduce() Ă© poderoso, mas pode ser difĂcil de entender e manter se nĂŁo for usado corretamente. Aqui estĂŁo algumas boas prĂĄticas e armadilhas que vocĂȘ deve evitar ao utilizĂĄ-lo.
A ImportĂąncia de Inicializar Corretamente o Acumulador
A inicialização do acumulador Ă© um dos aspectos mais crĂticos do reduce(). Se ele nĂŁo for inicializado corretamente, vocĂȘ pode obter resultados inesperados ou atĂ© mesmo erros no cĂłdigo.
âExemplo de erro comum:
const numeros = [10, 20, 30];
const soma = numeros.reduce((acc, valorAtual) => acc + valorAtual);
console.log(soma); // ERRO se o array estiver vazio
O que estĂĄ acontecendo aqui?
Caso o reduce() for chamado sem uma inicialização e o array estiver vazio, ele lança um erro porque não hå valor inicial para o acc.
đSolução Correta:
const soma = numeros.reduce((acc, valorAtual) => acc + valorAtual, 0);
console.log(soma)
//saĂda
// 60
O 0 garante que, mesmo se o array estiver vazio, o cĂłdigo nĂŁo quebre. Portanto Ă© sempre uma boa prĂĄtica inicializar o acumulador (acc).
â Dicas para Tornar o CĂłdigo Mais LegĂvel e Evitar Bugs
reduce() pode gerar cĂłdigo confuso se nĂŁo for bem estruturado. Aqui estĂŁo algumas dicas para tornĂĄ-lo mais legĂvel e seguro:
â Use nomes descritivos para os parĂąmetros
Evite nomes genéricos como [a] e [b]. Prefira nomes que indiquem o propósito das variåveis.
Exemplo ruim:
const resultado = valores.reduce((a, b) => a + b, 0);
Exemplo melhor:
const resultado = valores.reduce((acumulador, valorAtual) => acumulador + valorAtual, 0);
â Evite lĂłgica complexa dentro da função de reduce()
Se sua função reduce() estiver muito complexa, considere dividi-la em funçÔes auxiliares.
Condigo difĂcil de entender:
const categorias = compras.reduce((acc, { cliente }) => {
acc[cliente] = acc[cliente] ? acc[cliente] + 1 : 1
return acc;
}, {});
CĂłdigo mais legĂvel com função auxiliar:
function contarClientes(acc, {cliente}){
acc[cliente] = (acc[cliente] || 0) + 1
return acc
}
const categorias = compras.reduce(contarClientes, {})
Separar a lógica em uma função nomeada melhora a legibilidade e manutenção.
đQuando usar reduce() vs map(), filter() e forEach()
Nem sempre reduce() é a melhor escolha. Veja quando usar cada um dos métodos:
Método | Quando Usar | Exemplo
reduce() | Quando vocĂȘ precisa transformar um array em um Ășnico valor (nĂșmero, string, objeto, etc.). | Somar valores, agrupar Ătens.
map() | Quando vocĂȘ deseja transformar cada item do array sem reduzir para um Ășnico valor. | Criar um novo array com os preços com desconto.
filter() | Quando precisa manter apenas alguns elementos do array | Filtrar produtos acima de R$ 50,00.
forEach() | QUando deseja apenas iterar sobre o array sem criar um novo. | Exibir mensagens no console.
Exemplo prĂĄtico comparando reduce(), map(), filter() e forEach()
const numeros = [1, 2, 3, 4, 5];
// â Exemplo desenecessĂĄrio de reduce()
const soma = numeros.reduce((acc, num) => acc + num, 0);
// â
Uso correto de map()
const dobrados = numero.map(num => num * 2); // [2, 4, 6, 8, 10]
//â
Uso correto de filter()
const pares = numeros.filter(num => num % 2 === 0); // [2, 4]
// â
Uso correto de forEach()
numero.forEach(num => console.log(num)); // apenas exibe os valores
AĂ vocĂȘ deve estar se perguntando - Por que usar o reduce para realizar a soma de itens de um array Ă© um uso desnecessĂĄrio do reduce? E esta Ă© uma excelente pergunta, afinal fizemos vĂĄrios exemplos assim neste artigo. A verdade Ă© que usar o reduce para fazer a soma dos itens de um array Ă© como usar uma bazuca para caçar uma formiga, hĂĄ mĂ©todos mais simples que o reduce para realizar esta operação de somar itens de um array como por exemplo:
const soma = numeros.sum(); // entretanto funciona em algumas versÔes modernas do JavaScript
Caso nĂŁo haja suporte para array.sum(), outra abordagem Ă© utilizar o for ou o for-of:
let soma = 0;
for (let num of numeros){
soma += num
}
Este formato pode ser mais fĂĄcil de entender do que o reduce(), especialmente para iniciantes.
Quando o reduce() Ă© a melhor escolha?
Caso estejas lidando com dados mais complexos, onde precisa transformar a estrutura ao mesmo tempo que acumula valores, reduce() se torna extremamente Ăștil.
Por exemplo, se estivermos somando os valores de objetos dentro de um array:
const compras = [
{produto: "Camiseta", preco: 50},
{produto: "Calça", preco: 100},
{produto: "TĂȘnis", preco: 200}
];
const total = compras.reduce((acc, item) => acc + item.preco, 0);
console.log(total)
//saĂda
// 350
Neste caso, reduce() Ă© a melhor escolha por que estamos transformando um array de objetos em um Ășnico valor (a soma dos preços).
Portanto, Quando somamaos um array de nĂșmeros simples Ă© â desnecessĂĄrio o uso de reduce(), pois hĂĄ alternativas mais diretas e legĂveis. Ă â Ăștil o uso do reduce() quando agregamos dados mais complexos ou precisamos transformar a estrutura ao mesmo tempo.
O uso do reduce() para somas simples nĂŁo estĂĄ errado, necessariamente, mas pode tornar o cĂłdigo menos intuitivo do que outras abordagens đ.
đConclusĂŁo
O mĂ©todo reduce() Ă© muito Ăștil para agregar dados, mas pode ser complicado de entender e manter. Assim, sempre inicialize o acumulador corretamente, prefira nomes descritivos para os parĂąmetros, evite lĂłgicas complexas dentro da função reduce() e use map(), filter() ou forEach() quando forem mais adequados. Deste modo seus cĂłdigos serĂŁo mais simples, diretos e legĂveis. Usando o reduce teus cĂłdigos terĂŁo um aspecto mais profissional e terĂĄ mais fĂĄcil manutenção. Portanto, use e abuse do mĂ©todo reduce, mas considerando a moderação.





