E o reduce do JavaScript?
Tags: javascript, developer, webdev, beginners
Published: 2023-08-09 00:55:31

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 ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h5e06c14xekajstarlw1.png)

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 ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/htimhgytgip1dz299jk1.png)

## 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:

```js
const frutas = ['banana', 'maca', 'pera', 'banana', 'pera', 'abacaxi', 'pera', 'banana']
```

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

```js
{
  'banana': 3,
  'maca': 1,
  'pera': 3,
  'abacaxi': 1
}
```

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

```js
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);

```
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! 

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

}, {})
```
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! 

```js
frutas.reduce((acumulador, valorAtual) => {
  console.log(acumulador);
  console.log(valorAtual);
  return acumulador
}, {})
```
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á!

```js
frutas.reduce((acumulador, valorAtual) => {
  if (acumulador[valorAtual]) {
    acumulador[valorAtual] ++
  } 
  return acumulador
}, {})
```

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?_

```js
frutas.reduce((acumulador, valorAtual) => {
  if (acumulador[valorAtual]) {
    acumulador[valorAtual]++
  } else {
    acumulador[valorAtual] = 1
  }
  return acumulador
}, {})
```
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:

```js
const frutas = ['banana', 'maca', 'pera', 'banana', 'pera', 'abacaxi', 'pera', 'banana']
```
Teremos como retorno/saída:

```js
{ 
  banana: 3, 
  maca: 1, 
  pera: 3, 
  abacaxi: 1 
}
```

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.