DEV Community

Ana Laura
Ana Laura

Posted on • Updated on

E o reduce do JavaScript?

Olá pessoas! Meu objetivo com esse post é tentar ajudar no entendimento do famoso reduce().
Pode parecer um pouco confuso de início mas prometo tentar mostrar o poder desse método e como ele pode nos ajudar a resolver alguns problemas. 😻

O que é o reduce?

Em termos simples, o reduce() é uma função que recebe outra função como parâmetro, com o intuito de reduzir uma coisa em outra. Ele percorre cada elemento de um array, aplica uma função a esses elementos e acumula o resultado em um valor final. Esse valor final é o resultado da "redução" de todos os elementos do array. O valor final acumulado é retornado após todo o processo.

E os parâmetros do reduce?

Já falamos que o reduce recebe uma outra função como parâmetro, chamamos essa função de callback.
Essa callback é responsável por determinar como nossos elementos serão combinados. Além disso, a callback recebe alguns outros parâmetros, sendo eles:

  • Acumulador (accumulator): O valor acumulado resultante das ações anteriores.
  • Valor Atual (currentValue): O elemento atual do array sendo percorrido.
  • Índice Atual (currentIndex): O índice do elemento atual no array.
  • Array Original (array): O array original ao qual a função reduce() foi aplicada.

E também temos um segundo parâmetro, mas esse é opcional, que é o valor Inicial do Acumulador (initialValue).
Se a gente incluir ele nos parâmetros, a redução começa com esse valor. Se não fornecido, o primeiro elemento do array é quem assume essa posição de "valor inicial" e a redução começará a partir do segundo elemento.

Vamos pensar que estou percorrendo um array de números, primeiro vamos entender quem são o primeiro e o segundo parâmetro do reduce.

Um print de um código explicando o reduce, nesse código temos o reduce sendo aplicado a um array de números que recebe o nome de lista de números. Detalhamos também sobre cada parametro da callback passada para o reduce

Agora dê uma olhada nos parâmetros que a callback recebe:

Um print de um código explicando o reduce, nesse código temos o reduce sendo aplicado a um array de números que recebe o nome de lista de números. Detalhamos também sobre cada parametro do reduce

Reduzindo um array a um objeto com reduce 🙀

Agora que já entendemos os parâmetros do reduce vamos para a melhor parte: a prática!

Eu tenho uma lista com algumas frutas, onde alguma delas aparecem mais de uma vez. Observe:

const frutas = ['banana', 'maca', 'pera', 'banana', 'pera', 'abacaxi', 'pera', 'banana']
Enter fullscreen mode Exit fullscreen mode

Desafio: A ideia é pegar essa lista e descobrir quantas vezes cada um desses itens aparece, mostrando tudo bonitinho num objeto. Tipo assim:

{
  'banana': 3,
  'maca': 1,
  'pera': 3,
  'abacaxi': 1
}
Enter fullscreen mode Exit fullscreen mode

Primeiro, gostaria de propor resolver esse problema usando o famoso forEach.

const frutas = ['banana', 'maçã', 'pera', 'banana', 'pera', 'abacaxi', 'pera', 'banana'];

const contagemFrutas = {};
frutas.forEach(fruta => {
  if (contagemFrutas[fruta]) {
    contagemFrutas[fruta]++;
  } else {
    contagemFrutas[fruta] = 1;
  }
});

console.log(contagemFrutas);

Enter fullscreen mode Exit fullscreen mode

Dê uma olhada no código acima e tenta entender o que tá rolando! Logo abaixo eu dou uma explicação detalhada.

  1. Primeiro criamos um objeto vazio chamado contagemFrutas para armazenar as contagens de cada fruta.
  2. Depois utilizamos o forEach para percorrer cada elemento do array frutas. O forEach assim como reduce também recebe como parâmetro uma função que é executada para cada elemento do array.
  3. Dentro da função passada para forEach, verificamos se a fruta atual já existe como chave no objeto contagemFrutas.
  4. Se a fruta já existir no objeto contagemFrutas, incrementamos o valor correspondente a essa fruta.
  5. Caso a fruta ainda não exista no objeto contagemFrutas, criamos uma nova chave para essa fruta e atribuímos o valor inicial de 1.
  6. O processo acima vai repetir para cada fruta no array frutas, e no final teremos um objeto contagemFrutas contendo a contagem de cada tipo de fruta.

Por fim, usei o console.log para exibir o objeto contagemFrutas no console.

Agora que resolvemos o desafio usando o forEach(), bora ver resolver usando o reduce()!

Essa será a estrutura inicial do meu reduce. Vamos por partes!

frutas.reduce((acumulador, valorAtual) => {

}, {})
Enter fullscreen mode Exit fullscreen mode

Perceba que eu passo como valor inicial do meu reduce um objeto vazio. Isso é feito para que a gente possa pegar de volta esse objeto quando o reduce terminar. 🤓

Vamos continuar codando, mas antes dê um console.log() no acumulador e no valorAtual para conseguir visualizar melhor o retorno!

frutas.reduce((acumulador, valorAtual) => {
  console.log(acumulador);
  console.log(valorAtual);
  return acumulador
}, {})
Enter fullscreen mode Exit fullscreen mode

Você percebeu que o acumulador nos deu um objeto vazio? Isso acontece porque a gente começou ele assim na função reduce. Quando a gente joga um objeto vazio como o segundo parâmetro para a função reduce, ele é usado como valor inicial para o acumulador.

Bora continuar!

Lembra que quando usamos o forEach precisamos de uma condição para:

  1. Verificar se a fruta atual já existe como chave no objeto contagemFrutas.
  2. Se a fruta já existir no objeto contagemFrutas, incrementamos o valor correspondente a essa fruta.

No nosso reduce também precisamos fazer essa verificação, bora lá!

frutas.reduce((acumulador, valorAtual) => {
  if (acumulador[valorAtual]) {
    acumulador[valorAtual] ++
  } 
  return acumulador
}, {})
Enter fullscreen mode Exit fullscreen mode
  1. Primeiro, verificamos se a fruta atual (valorAtual) já existe como uma propriedade no objeto acumulador. Isso é feito verificando se acumulador[valorAtual] é verdadeiro (ou seja, se já existe). Se a fruta já existe no objeto, incrementa o valor da propriedade correspondente em 1 usando o operador de incremento ++.

Agora você deve tá se perguntando: Ana, e se não existir essa propriedade no objeto, o que fazemos?

frutas.reduce((acumulador, valorAtual) => {
  if (acumulador[valorAtual]) {
    acumulador[valorAtual]++
  } else {
    acumulador[valorAtual] = 1
  }
  return acumulador
}, {})
Enter fullscreen mode Exit fullscreen mode

Para isso adicionamos um else, caso não exista essa propriedade crie uma pra mim com o valor igual a 1!

E vualá !!! No final da iteração, o objeto acumulador é retornado para que seja usado como o acumulador na próxima iteração!

👀 Lembrando: Um objeto vazio é o nosso valor inicial do acumulador. Isso significa que, na primeira iteração, o objeto acumulador será vazio, mas à medida que as frutas são processadas, suas contagens serão todas armazenadas nesse objeto.

Se fornecermos como entrada o array de frutas abaixo, por exemplo:

const frutas = ['banana', 'maca', 'pera', 'banana', 'pera', 'abacaxi', 'pera', 'banana']
Enter fullscreen mode Exit fullscreen mode

Teremos como retorno/saída:

{ 
  banana: 3, 
  maca: 1, 
  pera: 3, 
  abacaxi: 1 
}
Enter fullscreen mode Exit fullscreen mode

Concluindo: Espero que este post tenha ajudado a esclarecer como usar o reduce() para resolver problemas como este.
O reduce é realmente poderoso em várias situações e pode ser incrivelmente útil.

Qualquer dúvida fiquem a vontade para comentar aqui, tentarei ajudar 💟

bjs bjs e até a próxima.

Top comments (2)

Collapse
 
gpa1992 profile image
Gabriel Proença Araujo

Muito massa!

Collapse
 
analaura profile image
Ana Laura

Obrigada Gabriel, fico feliz que tenha gostado :)