Reputation: 15369
On the whim of node school, I am trying to use reduce
to count the number of times a string is repeated in an array.
var fruits = ["Apple", "Banana", "Apple", "Durian", "Durian", "Durian"],
obj = {};
fruits.reduce(function(prev, curr, index, arr){
obj[curr] ? obj[curr]++ : obj[curr] = 1;
});
console.log(obj); // {Banana: 1, Apple: 1, Durian: 3}
is sort of working. For some reason, reduce
seems to skip the first element. I don't know why. Its first time through the array, index
is 1
. I tried putting in some logic like, if (index === 1){//put 'prev' as a property of 'obj'}
. But that seems really convoluted. I'm certain that this is not how node school wants me to solve this problem. However, I wonder what's a good way to access the zeroth element in the array you're reducing. Why is this zeroth element seemingly ignored by the reduction procedure? I guess I could pass in fruits[0]
after the callback so I start with that value initially. What's the best way to access this zeroth element?
Upvotes: 12
Views: 11670
Reputation: 1
accordin whit the official documentation, you should set the initial value.
var fruits = ["Apple", "Banana", "Apple", "Durian", "Durian", "Durian"];
fruits.reduce(function(prev, curr, index, arr){
//...
}, 0);
The initial value was cero(0).
console.log(obj); // {Banana: 1, Apple: 2, Durian: 3}
I took this from documentation:
initialValue Optional A value to which accumulator is initialized the first time the callback is called. If initialValue is specified, callbackFn starts executing with the first value in the array as currentValue. If initialValue is not specified, accumulator is initialized to the first value in the array, and callbackFn starts executing with the second value in the array as currentValue. In this case, if the array is empty (so that there's no first value to return as accumulator), an error is thrown.
Upvotes: 0
Reputation: 26141
The syntax of reduce()
is:
arr.reduce( callback [, initial] );
If you omit initial
value, callback
will get called 5 times, with arr[0]
passed in as the initial value of previous
:
callback( previous=arr[0], current=arr[1], index=0, array=arr );
callback( previous , current=arr[2], index=1, array=arr );
callback( previous , current=arr[3], index=2, array=arr );
callback( previous , current=arr[4], index=3, array=arr );
callback( previous , current=arr[5], index=4, array=arr );
If you include initial
value, callback
will get called 6 times with initial
passed in as the initial value of previous
:
callback( previous=initial, current=arr[0], index=0, array=arr );
callback( previous , current=arr[1], index=1, array=arr );
callback( previous , current=arr[2], index=2, array=arr );
callback( previous , current=arr[3], index=3, array=arr );
callback( previous , current=arr[4], index=4, array=arr );
callback( previous , current=arr[5], index=5, array=arr );
Because you're building an object, I recommend you passed in an empty object { }
as the initial
value:
const fruits = [ "Apple", "Banana", "Apple", "Durian", "Durian", "Durian" ];
const initial = { };
const result = fruits.reduce( function (previous, current, index, array) {
previous[current] = !previous[current] ? 1 : previous[current] + 1;
return previous;
},
initial
);
console.log( "result: ", result );
// Output:
//
// result: {
// "Apple": 2,
// "Banana": 1,
// "Durian": 3
// }
Reference:
Upvotes: 9
Reputation: 1985
This question is quite old and the answer is already given to the point.
In addition with that I am including the description from offical Documentation that has some other key point and it will be helpful for the new comers
From the official documentation of Array.prototype.reduce()
The reduce() method executes the callback once for each assigned value present in the array, taking four arguments:
- accumulator
- currentValue
- currentIndex
- array
The first time the callback is called, accumulator and currentValue can be one of two values. If initialValue is provided in the call to reduce(), then accumulator will be equal to initialValue, and currentValue will be equal to the first value in the array. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.
Note: If initialValue is not provided, reduce() will execute the callback function starting at index 1, skipping the first index. If initialValue is provided, it will start at index 0.
If the array is empty and no initialValue is provided, TypeError will be thrown.
If the array only has one element (regardless of position) and no initialValue is provided, or if initialValue is provided but the array is empty, the solo value will be returned without calling callback.
And also a bit modified one,
var fruits = ["Apple", "Banana", "Apple", "Durian", "Durian", "Durian"], obj = {};
fruits.reduce((prev, curr, index, arr) => {
if(!prev.hasOwnProperty(curr)) {
prev[curr] = 0;
}
prev[curr]++;
return prev;
}, obj);
console.log(obj);
Upvotes: 0
Reputation: 119867
If no
initialValue
was provided, thenpreviousValue
will be equal to the first value in the array andcurrentValue
will be equal to the second.
Additionally, you have to return a value from the function. That value becomes the value of previousValue
on the next iteration.
I'd suggest you "carry" your aggregator obj
as the initial value.
var fruits = ["Apple", "Banana", "Apple", "Durian", "Durian", "Durian"];
var obj = fruits.reduce(function(carry, fruit){
if(!carry[fruit]) carry[fruit] = 0; // If key doesn't exist, default to 0
carry[fruit]++; // Increment the value of the key
return carry; // Return aggregator for next iteration
}, {});
alert(JSON.stringify(obj));
Here's a simple diagram:
fruit carry (before operation) carry (after operation, returned value)
1st iteration: Apple {} {Apple:1}
2nd iteration: Banana {Apple:1} {Apple:1, Banana:1}
3rd iteration: Apple {Apple:1, Banana:1} {Apple:2, Banana:1}
4th iteration: Durian {Apple:2, Banana:1} {Apple:2, Banana:1, Durian:1}
5th iteration: Durian {Apple:2, Banana:1, Durian:1} {Apple:2, Banana:1, Durian:2}
6th iteration: Durian {Apple:2, Banana:1, Durian:2} {Apple:2, Banana:1, Durian:3}
Upvotes: 16