We must understand, first, that the Array.prototype.reduce
works on an array. In this case, the array that will be reduced is the array itself under which we call the method reduce
. Beyond the array (which is the "argument" this
), reduce
requires a reducing function and accepts an initial value.
In the example we are dealing with in this answer, we call reduce
thus:
const result = [1, 2, 3, 1, 2, 1].reduce(countReducer, {});
So:
- The array to be reduced will be
[1, 2, 3, 1, 2, 1]
("argument" this
).
- The reducing function is
countReducer
(first argument of the method).
- The starting value is
{}
(second argument of the method).
With that, to each array element [1, 2, 3, 1, 2, 1]
, the reducing function we pass will be called. The trick to "understand" is to know that the value that the reducer function returns will be used as the parameter accumulator
for the next iteration. It is therefore important to define an initial accumulator in most cases.
- Read to documentation, who has an example explaining step by step.
It is important to note that if you do not set initial accumulator, the first element of the array will be used as such. However, in that situation, according to the logic of what we want to do, this is not desirable.
Going now to the full code, we have:
function countReducer(accumulator, current) {
// Caso o item da iteração atual ainda não tenha sido contabilizado.
if (!accumulator[current]) {
// Inicializamos o contador para o item da iteração atual como 0:
accumulator[current] = 0;
}
// Incrementamos o contador para o item da iteração atual:
accumulator[current] += 1;
// Retornamos o acumulador para as próximas iterações:
return accumulator;
}
const result = [1, 2, 3, 1, 2, 1].reduce(countReducer, {});
console.log(result);
1 | function countReducer(accumulator, current) {
2 | // Caso o item da iteração atual ainda não tenha sido contabilizado.
3 | if (!accumulator[current]) {
4 | // Inicializamos o contador para o item da iteração atual como 0:
5 | accumulator[current] = 0;
6 | }
7 |
8 | // Incrementamos o contador para o item da iteração atual:
9 | accumulator[current] += 1;
10 |
11 | // Retornamos o acumulador para as próximas iterações:
12 | return accumulator;
13 | }
14 |
//// ↓↓
15 | const result = [1, 2, 3, 1, 2, 1].reduce(countReducer, {});
16 | console.log(result);
Let’s understand what we want to happen and then understand the code above, line by line.
Assuming we have an array like [1, 2, 3, 1, 2, 1]
, we want to return an object with the amount of each element of the array, so:
{
1: 3,
2: 2,
3: 1
}
And how the reduce
will help us get there?
Starting from the first line to be executed (15
), where we invoke the method reduce
, note that we passed, as initial value, a literal object "empty" ({}
). This is our object accumulator
, only that he still finds himself "empty"!
From this, the reduce
will call the function countReducer
for each array element. So the parameter accumulator
will be given by the function countReducer
return in previous iteration (except in first iteration, in which accumulator
is the empty object that we define in the second argument of the method).
Starting from the first iteration (in which {}
is still empty), we need to add the elements with the respective counts. For this, we use the notation accumulator[current]
. That’s the bracket notation for object access in Javascript.
In the specific case of the first iteration, for example, accumulator
will still be empty. In this case, how current
corresponds to the first element of the array, what we are doing is, this:
accumulator[current]
Is the same as:
accumulator[1]
That means we’re trying to access the property 1
in the object accumulator
. In the case of first iteration, this property will not yet be defined, therefore the expression accumulator[current]
(in the first iteration) return undefined
.
In this case, as the counter has not yet been defined, we need to create a way to define the counter as 0
so that we can start counting for the element in question. That’s what the if
(lines 3~6) is doing. It checks if the counter refers to the element (current
) current has not yet been defined and if it has not actually been defined, arrow the current element counter to 0
.
So on line 9 we can increase the count for the current element. Again we have the expression accumulator[current]
, which basically means:
Access, in the accumulator, the property whose key is (dynamically) current
and increment 1, indicating that we went through this item once.
This same logic is processed for each element of the array.
The codic is wrong, the variable
numero
was not defined.– Dakota
Actually the code is right, @Mariaeduarda...
– Luiz Felipe
@Mariaeduarda already edited, had made the publication without the array
– danielhcr22