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;
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
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)
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)
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)
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')
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)
Esse foi o primeiro exemplo que utilizamos aqui, mas dessa vez ao executarmos temos um resultado diferente:
console.log(totalVotes) // 'angular'
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)