JavaScript

17 set, 2018

Implementando reduce em JavaScript

Publicidade

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.