I'm trying to recreate the _.reduce method from the underscore library from scratch but I'm failing three test cases. 1. Should continue to call iterator even if the iterator returns undefined. 2. Should pass every item of the array into the iterator if a memo is passed in. 3. Should pass the second item of the array into the iterator first if a memo is not passed in. I've been looking at the docs and I thought that iterator(accumulator, collection[1], 1, collection) would cover the third case but I guess not.
_.reduce = function(collection, iterator, accumulator) {
// TIP: To support both arrays and objects, try re-using each() here
if (accumulator === undefined) {
accumulator = collection[0];
iterator(accumulator, collection[1]);
}
_.each(collection, function(val) {
iterator(accumulator, val);
}
);
return accumulator;
};
Some issues:
In case accumulator
is undefined, your code first calls iterator
with collection[1]
, but if collection
is not an array, this will not represent the second element of the collection. For instance, the second element in {a:1, b:2}
would be collection.b
.
In case accumulator
is undefined, your code will still continue to execute _.each
which will call iterator
on the first element of the collection, which you wanted to avoid...
Your code ignores the value returned by the call of iterator
. It should capture this return value and assign it to accumulator
The iterator
should be called with a third argument: the index/key of the value.
The iterator
should be called with a fourth argument: the complete collection that is being iterated
Correction:
_.reduce = function(collection, iterator, accumulator) {
_.each(collection, function(val, i) {
if (accumulator === undefined && i === 0) accumulator = val;
else accumulator = iterator(accumulator, val, i, collection);
});
return accumulator;
};
// Tests
console.log(_.reduce([1,2,3], (a, b) => a+b, 1) === 7);
console.log(_.reduce([1,2,3], (a, b) => a+b) === 6);
console.log(_.reduce({a: 1, b: 2, c:3}, (a, b, i) => a+b, 0) === 6);
console.log(_.reduce({a: 1, b: 2, c:3}, (a, b, i) => a+i, "") === "abc");
console.log(_.reduce([], (a, b) => a+b, 0) === 0);
console.log(_.reduce([], (a, b) => a+b) === undefined);
console.log(_.reduce([1,2,3], (a, b, i, all) => a + b * all[i-1]
) === 9);
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd.min.js"></script>