Reduce is a very handy function.
Solve this problem for instance:
what is the total of all the numbers in this array added together :
var numbers = [2,66,756,432,5,6,7,8989,765,434,22,12,12,45,6,7,8,453,67,54,33,22,123,999];
With reduce this is very simple :
var example = _.reduce(numbers, function(a, b){
return a + b;
})
console.log(example);
13325 will be printed to the console.
Reduce takes an array, and reduces it to one item. It does this by setting an accumulator equal to the function provided with the accumulator as the first parameter and item as the second.
There's actually a lot that can be done with reduce, because reduce is more generic in nature than functions like map or filter, that are built with specific uses in mind.
We can concatenate words:
var words = ["Yesterday", "I", "went", "to", "the", "store."]
var example2 = _.reduce(words, function(a,b){
return a + b;
})
console.log(example2); Will print : YesterdayIwenttothestore.
You may notice there are no space between the words, here's how to fix that:
_.reduce(words, function(a, b){
return a + " " + b;
})
This will print : Yesterday I went to the store.
What if you want to know if every word in an array has a length of 8 or greater?
var example3 = _.reduce(words, function(a, b){
return a && b.length >= 8;
}, true)
console.log(example3) Will print out false. All of the words in the array names words do not have a length of 8 or greater.
However, if you run it with this array you will get true:
var words2 = ["Yesterday", "Kentucky", "Mongolia", "Computer"];
You might notice something about the way we called reduce this time, there is a third argument there, this time it is the boolean value of true.
Yes, reduce is designed to accept three arguments. The collection, a function, and an accumulator. If you provide no accumulator, then reduce makes the first item in the array the accumulator. However, if you do provide an accumulator, like we did with true, then that will be the accumulator.
So, if I walk through the call to reduce above in example3 it goes something like this:
a, which is the accumulator = true. The function is instructed to return a, which is true, however notice the && operator. If the left side of an && operator is true then the right side is looked at and returned. So, because a equals true, the right side is examined, and that value equates to either true or false. If the right side equates to true, then true is returned and the accumulator(you'll understand this when we walk through the rewrite) is set to true. This will continue until the right side, and only if the right side, returns a value of false. If that happens, then the accumulator(a), is set to false.
If we look at the statement return a && b.length >= 8, if the left side equals false, then the right side will never again be examined, that's just how the && operator works. If that confuses you, google it. MDN does a good job of explaining the operators. That's Mozilla Developer's Network.
So, if this function receives on return of false, then no matter what, it will return false.
Whoops, we've actually just written the blue print of the Underscore Every function.
Okay, so we've gone into a lot without even re writing reduce yet, so let's just get to it:
var _ = {};
_.reduce = function(collection, iterator, accumulator) {
_.each(collection, function(item){
if(accumulator === undefined){
accumulator = item;
}
else{
accumulator = iterator(accumulator, item);
}
})
return accumulator;
}
As you can see reduce uses each so I'll include that here:
_.each = function(collection, iterator){
if(Array.isArray(collection)){
for(var i = 0; i < collection.length; i ++){
iterator(collection[i], i, collection);
}
}
else{
for(var key in collection){
iterator(collection[key], key, collection);
}
}
}
Let's walk through reduce:
First, reduce accepts an array, a function, and an accumulator.
Next, it calls each, and feeds it the collection, and hard wires in a function that takes item as an argument. The first thing it does it to determine whether or not an accumulator has been provided as an argument when reduce was called. If not, then the first iteration involves setting accumulator = to item.
The next iteration will take that accumulator and set it equal to the value of the function provided when reduce was called, and this function is fed the accumulator, and the item. These two arguments are represented in our above examples as a and b.
Finally, the accumulator is returned.
Questions?
No comments:
Post a Comment