DEV Community

Cover image for Esse tal de Reduce e como podemos usar.
Rafael Nogueira
Rafael Nogueira

Posted on

Esse tal de Reduce e como podemos usar.

O Reduce é utilizado em um array, iterando em cada item até retornar um único valor. Ele recebe uma função e um valor inicial. Essa função recebe 4 argumentos:

  • a variável que servirá como acumulador
  • o elemento atual
  • o index
  • o array original
array.reduce(function(accumulator, element, index, array) => {}, initialValue; 
Enter fullscreen mode Exit fullscreen mode
const data = [1, 2, 3, 4, 5]
const reducer = function(accumulator, item) {
    return accumulator + item
}
const initialValue = 0;
const total = data.reduce(reducer, initialValue) // 15
Enter fullscreen mode Exit fullscreen mode
const votes = ["angular", "angular", "react", "react", "react","vue", "ember", "vanilla"]
const initialValue = {};
const reducer = function(poll, vote) {
    if(!poll[vote]) {
        poll[vote] = 1
    } else {
        poll[vote] = poll[vote] + 1
    }

    return poll;
}
const totalVotes = votes.reduce(reducer, initialValue)
Enter fullscreen mode Exit fullscreen mode

Reduce e performance

Vamos ver dois exemplos com funções que utilizamos diariamente e como o uso do reduce pode ser útil.

Dado um array, iremos retornar um novo array com a mesma quantidade de itens sendo que seus valores são o dobro do valor inicial.

const data = [1, 2, 3, 4, 5, 6]
const initialValue = [];
const reducer = function(total, value){
    total.push(value * 2)
    return total;
}

const doubled = data.reduce(reducer, initialValue)
Enter fullscreen mode Exit fullscreen mode

Esse mesmo resultado pode ser alcançado utilizando Map, inclusive com menos linhas.

Um outro caso seria filtrar o mesmo array, retornando apenas os números pares.

const data = [1, 2, 3, 4, 5, 6]
const initialValue = [];
const reducer = function(total, value){
    if(value % 2 === 0) {
        total.push(value)
    }
    return value;
}
const odd = data.reduce(reducer, initialValue)
console.log(odd)
Enter fullscreen mode Exit fullscreen mode

Nesse segundo caso podemos utilizar o filter, que como o próprio nome diz, irá filtrar o array retornando o valor que desejamos.

Inclusive esses métodos podem ser utilizados em conjunto, para filtrar e retornar os números pares com valor dobrado.

Tendo isso em mente e ainda possuindo um código bem mais enxuto de se escrever, porque optaríamos por utilizar o reducer para realizar essa operação?

Nos exemplos utilizados, foram usados arrays pequenos, controlados. Mas qual seria o resultado disso em arrays muito maiores? Vamos comparar.

let bigData = []
for(let i = 0; i<1000000; i++) {
    bigData[i] = i
}

console.time('filteredMapped')
const filteredMapped = bigData.filter(value => value % 2 === 0)
.map(value => value * 2)
console.timeEnd('filteredMapped')

console.time('reducer')
const reducer = bigData.reduce(function(acc, value){
    if(value % 2 === 0) {
        acc.push(value * 2)
    }
    return acc
}, [])
console.timeEnd('reducer')
Enter fullscreen mode Exit fullscreen mode

Notou a diferença no tempo de execução das funções? Se tratando de lidar com muitas informações, podemos ter um considerável ganho de performance mesmo tendo que escrever algumas linhas a mais.

A lógica utilizada é a mesma, mas onde temos um ganho é que no primeiro caso é necessário que o método filter passe por todas os 1000000 itens, para só depois o map realizar sua operação nos 500000 restantes.

Enquanto com o uso do reduce essa operação é realizada de uma única vez, nos itens que filtramos.

Atenção a possíveis erros

const votes = ["angular", "angular", "react", "react", "react","vue", "ember", "vanilla"]
const initialValue = {};
const reducer = function(poll, vote) {
    if(!poll[vote]) {
        poll[vote] = 1
    } else {
        poll[vote] = poll[vote] + 1
    }

    return poll;
}
const totalVotes = votes.reduce(reducer)
Enter fullscreen mode Exit fullscreen mode

Esse foi o primeiro exemplo que utilizamos aqui, mas dessa vez ao executarmos temos um resultado diferente:

console.log(totalVotes) // 'angular'
Enter fullscreen mode Exit fullscreen mode

O que será que aconteceu aqui? Notou alguma diferença na função desse exemplo e o anterior?

O problema é que esquecemos de informar o valor initial(initialValue) para o nosso reduce.

Tá, mas nesse caso não era para ter dado erro na execução? Sim... e não!

Na intenção de nos ajudar o Javascript percebe que nenhum valor inicial foi informado e assume que o primeiro item do array é esse valor. Sendo a string 'angular', um valor primitivo ele não recebe propriedades e por suas vez seu valor é falso. No final, o valor inicial é retornado.

Um outro possível caso, é esquecermos de retornar o accumulator ao final do reduce e com isso o retorno acaba sendo undefined.

Top comments (0)