Eu gastei muito tempo tentando entender as funções map/reduce, e depois disso ainda mais tentando usá-las no dia a dia. Por esse motivo eu decidi fazer esse artigo, mas eu não quero simplesmente explicar como ou quando usar essas funções; vamos implementar juntos a função reduce e usando somente essa função implementaremos algumas outras funções que estão na moda em linguagens que suportam programação funcional ou programação reativa como map, filter, flatMap e outras.
Por que implementar reduce?
Porque vai nos ajudar a entender realmente como essa função funciona. Além disso, a nossa função reduce poderá ser usada em qualquer objeto iterável de JavaScript. E o mais importante é que você pode usar o que aprender aqui para implementar essa função em qualquer outra linguagem que esteja usando.
O que é reduce?
A função reduce retorna o resultado de aplicar uma dada função a um objeto iterável, sempre acumulando o resultado a cada iteração. Então a ideia é (como o nome diz) transformar o objeto iterável em um único objeto, então essa função é perfeita para, por exemplo, somar todos os elementos de um array.
Implementando reduce
Uma possível implementação de Reduce, é:
const reduce = function(iterable, reduceFn, accumulator){ for(let i of iterable){ accumulator = reduceFn(accumulator, i) } return accumulator }
Como você pode ver, nossa função reduce recebe três parâmetros: o primeiro é o objeto iterável (iterable), o segundo a função (reduceFn) que vai ser executada a cada elemento do objeto iterável (essa função recebe dois parâmetros, o primeiro é o acumulador e o segundo um elemento do objeto iterável), o último é o valor initial para o acumulador.
Olhando essa implementação, podemos ver que a função reduce é só uma iteração sobre cada elemento do objeto iterável que substitui o acumulador pelo resultado da execução da função dada ao atual valor do acumulador e o próximo elemento.
Nós podemos testar nosso código usando-a para somar todos os elementos em um array:
console.log(reduce([1,2,3], (acc,elem)=>acc+elem , 0)) // Imprime 6
Se você seguir a função passo-a-passo, na primeira iteração o acumulador é 0 e o elemento é 1, então ele vai acumular 1 (0 + 1), na segunda iteração o acumulador é 1 (da iteração anterior) e o próximo elemento é 2, então ele vai acumular 3 (1 + 2), para a última iteração o acumulador é 3 (da iteração interior) e o próximo elemento é 3, então ele acumulará 6 (3 + 3), como não há mais nenhum elemento, nós retornamos o acumulador (6).
Nossa função reduce utiliza a expressão for … of , e nós fizemos dessa forma para que ela possa ser usada em qualquer objeto iterável do javascript como um Set, por exemplo:
const mySet = new Set([1,2,3]) console.log(reduce(mySet, (acc,elem)=>acc+elem , 0)) // Imprime 6
Agora nós podemos implementar novas funções utilizando somente a função reduce. Nós já vimos como é fácil implementar uma função para somar todos os elementos:
const sum = function(iterable){ return reduce(iterable ,(acc, elem)=> acc+elem, 0) } console.log(sum(1,2,3)) // Imprime 6
Essa foi fácil, agora nós podemos também implementar uma função para calcular o maior número em um array:
const max = function(it){ return reduce(it,(acc, elem)=> Math.max(acc,elem),it[0] ) } console.log(max([0,2,3,-1,9])) // Imprime 9
Ou o mínimo:
const min = function(it){ return reduce(it,(acc, next)=> Math.min(acc,elem),it[0]) } console.log(max([0,2,3,-1,9])) // Imprime -1
Espero que tenham gostado! No próximo artigo veremos como implementar as funções map, filter e flatMap usando somente a função reduce.