Executando verificação de segurança...
2

🧮 Reduce em arrays: um método subestimado

Um Array é uma estrutura presente na maioria das linguagens, que tem como objetivo armazenar diversos valores de mesma natureza em uma lista, facilitando a manipulação dos dados nesta lista, visto que armazena-los separadamente (criando uma referência na memória para cada um) seria muito mais trabalhoso e complexo de entender. Exemplo:

    const corDisponivel1 = "vermelho";
    const corDisponivel2 = "amarelo";
    const corDisponivel3 = "azul"
    
    ========= Array =========
    const coresDisponiveis = ["vermelho", "amarelo", "azul"]

Para manipular um array, são disponibilizados vários métodos, cada um com seu objetivo - Adicionar, remover, alterar, etc. No Javascript, alguns dos mais comuns são:

  • push - Adicionar um valor ao final do array
  • pop - Remove o último valor do array
  • join - Junta todos os valores de um array em uma string
  • map - Executa uma função para modificar cada elemento presente no array. (Retorna um novo array, já modificado).
  • filter - Executa uma função para filtrar o array de acordo com uma condição (Retorna um novo array, já filtrado)

Existem muitos outros, por exemplo, o reduce, que se tratando de um array numérico, serve para obter a soma ou a diferença desta lista. Exemplo:

    const valores = [10, 15, 20]
    
    const valorTotal = valores.reduce((acumulador, valorAtual) => acumulador + valorTotal, 0)
    console.log(valorTotal) //45

Só para clarear o que aconteceu no exemplo a cima, o reduce executa uma função para cada valor presente no array, onde ele armazena no acumulador o resultado de cada operação. O 0 no final, indica o valor inicial do acumulador. Ou seja, em um primeiro momento, somamos 0 + 10, onde 10 é o valorAtual, que é o 1º valor do array. O resultado dessa soma, armazenamos no acumulador, e executamos novamente a função. Agora, o calculo será 10(acumulador) + 15(valorAtual do array), e teremos 25, e assim por diante, até que não tenha mais nenhum valor no array.

Mas o objetivo deste Tab não é explicar o funcionamento do reduce, mas sim sua importância. Em cursos, vídeos, etc. a explicação pararia por aqui, e você concluiria que o reduce serve apenas para obter a soma ou a diferença de um array, mas ele é muito mais do que isso, e este é o objetivo deste Tab: Mostrar do que o reduce é capaz.

O verdadeiro reduce

O objetivo do reduce é reduzir/transformar um array em uma nova estrutura de dados (uma string, um número, um objeto).

Ok Matheus, mas onde eu deixo explícito para o reduce qual o novo tipo de dado eu quero receber ?

Se você olhar o exemplo anterior, nós passamos dois argumentos para o reduce: A função, contendo o acumulador e o valorAtual, e o número 0. No nosso exemplo, o número 0 corresponde ao valor inicial do novo tipo de dado que queremos obter. Ou seja, como segundo parâmetro do reduce, nós passamos qual a nova estrutura de dados queremos, e qual seu valor inicial.

Outro exemplo utilizando o reduce

Eu tenho uma aplicação que registra operações financeiras, contendo entradas, saídas, e o valor total. O valor da operação e o seu tipo (entrada ou saída) é informada em um formulário pelo usuário. Depois de alguns registros, temos a seguinte estrutura:

const registros = [
    {
        nome: "Mercado",
        valor: 200
        tipo: "saida"
    },
    {
        nome: "Salário",
        valor: 1200
        tipo: "entrada"
    },
    {
        nome: "Luz e água",
        valor: 300
        tipo: "saida"
    }
]

O objetivo é gerar um relatório ao final do dia, mostrando o total das entradas, total das saídas, e o saldo final (entradas - saidas). Se você acha que reduce é só para obter somas ou diferenças, você iria separar em uma array apenas entradas, depois em outro array apenas saidas, fazer o reduce em cada um destes arrays, e depois soma-los. Mas perceba a complexidade em fazer isso, visto que apenas 1 reduce resolve o problema. Vamos lá:

const resumoDasOperacoes = registros.reduce((acumulador, operacaoAtual) => {
    if (operacaoAtual.tipo === "entrada") { //Se a operacao for entrada...
        acumulador.valorEntrada += operacaoAtual.valor //Incremente o valor no valorEntrada
    } else { //Se não for entrada, então só pode ser saida...
        acumulador.valorSaida += operacaoAtual.valor //Incremente o valor no valorSaida
    }
    acumulador.saldoTotal = acumulador.valorEntrada - acumulador.valorSaida //Cálculo do saldo
    
    return acumulador // Retornando o acumulador com os seus valores.
},
{ //2º parâmetro, informando o estado inicial da estrutura que eu quero (Nosso acumulador)
    valorEntrada: 0,
    valorSaida: 0,
    saldoTotal: 0
}
)

console.log(resumoDasOperacoes) //{valorEntrada: 1200, valorSaida: 500, saldoTotal: 700}

Reduzimos/transformamos um array em uma nova estrutura de dados, que neste caso é um objeto. Claro que ambos os exemplos foram somando valores, mas o mesmo conceito pode ser aplicado para separar strings, fazer calculos complexos, etc.

Se ficou com alguma dúvida, deixe nos comentários. Esse Tab ficou maior do que eu gostaria, mas espero que você tenha uma visão melhor sobre este método que é poderoso, mas pouco comentado. Abraços.

2

O Tab está do tamanho exato e bem explicado, é uma ótima aplicação do reduce. Normalmente os exemplos se resumem a contadores únicos ou médias, sendo que o método serve para muito mais do que isso, como no seu exemplo, parabéns.

1

Obrigado pelo feedback. Cara, realmente todas as vezes que eu vi reduce em algum curso ou vídeo, o máximo que explicavam era sobre essa questão de somar os valores. É muito vago para um método tão útil em muitos casos. Senti a necessidade de dar outro ponto de vista sobre ele.

2

Acho que um exemplo com string (que você comentou no final) até que seria válido. A ideia de só usar para operações numéricas ainda ficou um pouco no ar. De resto, perfeito. O exemplo final já deu uma outra ideia do método, que, realmente, é pouco usado.

1

Eae Enzo. Obrigado pelo feedback. Depois de postar, eu fiquei com essa sensação também, pois no post eu digo que reduce é muito mais que operações numéricas, mas o exemplo foi usando isso. Pensei em editar, mas este exemplo, mesmo sendo com números, acredito que da uma nova visão do reduce.

Dando um exemplo com string, imagina uma escola de educação a distância, onde eu quero separar os alunos que já renovaram a matrícula dos que não, para mandar um email de acordo com essa informação. Nos dados do usuário, poderia ter uma propriedade renovou, que é um boolean (verdadeiro ou falso), e com base nisso, de um array que contém todos os alunos, eu separo em outros dois arrays: Um dos que renovaram, e outro dos que não, e mando um e-mail diferente de acordo com isso.