Entendendo o método `reduce` em JavaScript

Mar 27 2023
A palavra reduzir significa literalmente “tornar algo menor”. É um conceito de programação funcional que aplica uma função contra um acumulador e cada elemento em um array para reduzi-lo a um único valor.

A palavra reduzir significa literalmente “tornar algo menor”. É um conceito de programação funcional que aplica uma função contra um acumulador e cada elemento em um array para reduzi-lo a um único valor. É um conceito muito poderoso e é usado no desenvolvimento de bibliotecas e estruturas complicadas como Redux ou Ramda .

Em JavaScript, a redução está disponível como um método de array. Eu tenho usado o método de redução no meu trabalho por um longo tempo. No entanto, notei que muitos de meus amigos e colegas lutam para entender e usar esse método de maneira eficaz. Por isso, decidi escrever este artigo para explicar o método de redução em termos mais simples. Esse poderoso conceito pode ajudar a otimizar o código e implementar sistemas e lógica complexos. Espero que isso ajude mais pessoas a entendê-lo corretamente.

Vamos esquecer o reducemétodo Array por enquanto. Criaremos nossa própria reducefunção do zero para entender melhor o que ela realmente faz.

Quebrando as coisas

Para começar, vamos dividir diferentes componentes na função de redução .

  • Acumulador — É uma variável que armazena o resultado após cada etapa de redução. Ele também se tornará a entrada para a próxima etapa.
  • Redutor — É uma função que pega o acumulador e cada elemento do array. Ele deve retornar o valor do acumulador para a próxima etapa. Ele define cada passo em uma redução.
  • Valor Inicial — É o valor do Acumulador para o primeiro passo de redução. Você pode considerar isso como algum tipo de valor semente. O resultado final da redução depende apenas do valor inicial e do redutor .
  • The Input Array — Não há necessidade de mais explicações com este .

Usarei o TypeScript para criar a função neste artigo. Isso me permitirá usar tipos estáticos para definir melhor a função e ajudar os leitores a entender melhor.

type Reducer<TEle, TAcc> = (acc: TAcc, ele: TEle) => TAcc;

function reduce<TEle, TAcc>(
 arr: TEle[],
 reducer: Reducer<TEle, TAcc>,
 initialValue: TAcc
) {
// TODO: Implement
}

Considere um exemplo simples de redução — “Soma dos elementos em uma matriz” . Deve ser bastante fácil implementar a lógica para isso. Vamos fazê-lo:

const arr = [1,2,3,4,5,6,7,8,9,10];

let sum = 0;

for (let num of arr) {
    sum = sum + num;
}

console.log(sum);

soma de elementos como componentes de uma redução

Agora podemos facilmente reescrever o mesmo código como uma combinação de diferentes componentes de redução.

const arr = [1,2,3,4,5,6,7,8,9,10];
const initialValue = 0;
const reducer = (acc: number, ele: number) => acc + ele;

let acc = 0;

for (let ele of arr) {
    acc = reducer(acc, ele);
}

Agora, podemos usar as informações acima para concluir nossa reducefunção.

type Reducer<TEle, TAcc> = (acc: TAcc, ele: TEle) => TAcc;

function reduce<TEle, TAcc>(
 arr: TEle[],
 reducer: Reducer<TEle, TAcc>,
 initialValue: TAcc
) {
    let acc = initialValue;
    for (let ele of arr) {
        acc = reducer(acc, ele);
    }
    return acc;
}

O parâmetro redutor no método de redução também leva o índice e a matriz de entrada como argumentos, mas, em essência, é implementado da mesma forma que a função de redução que acabamos de criar.

Qual o proximo?

Agora, há algumas coisas que você pode fazer mais para ser realmente bom em usar o reduce é praticar e tentar implementar lógicas de redução complexas. Alguns dos itens que você pode experimentar são:

  1. Escreva uma função que receba uma matriz de números e retorne o produto de todos os números.
  2. Escreva uma função que receba um array de strings e retorne o número total de caracteres em todas as strings combinadas.
  3. Escreva uma função que receba uma matriz de números e retorne a média (média) dos números.
  4. Escreva uma função que receba uma matriz de objetos com uma valuepropriedade numérica e retorne a soma de todas as valuepropriedades.
  5. Escreva uma função que receba um array de strings e retorne a string mais longa do array.
  6. Escreva uma função que receba um array de números e retorne o número máximo no array.
  7. Escreva uma função que receba um array de números e retorne o número mínimo do array.
  8. Escreva uma função que receba uma matriz de objetos com uma valuepropriedade numérica e retorne a média de todas as valuepropriedades.
  9. Escreva uma função que receba uma matriz de objetos com uma namepropriedade e retorne uma única string que concatene todas as namepropriedades, separadas por vírgulas.
  10. Escreva uma função que receba um array de números e retorne um novo array com apenas os números pares do array original.