Add a basic reduce implementation

This commit is contained in:
Andrew Stewart 2015-02-23 15:20:50 -08:00
parent 2eaea42a72
commit 4e363e7930
2 changed files with 71 additions and 1 deletions

View File

@ -136,11 +136,42 @@ function invoke(collection, fn) {
return vals;
}
function reduce(collection, iteratee, accumulator, thisVal) {
var isArray = H.isArray(collection);
if (!isArray && !H.isObjectLoose(collection)) {
return null;
}
if (iteratee == null) {
iteratee = identity;
}
if (accumulator == null) {
if (isArray) {
accumulator = collection.shift();
} else {
for (var key in collection) {
accumulator = collection[key];
delete collection[key];
break;
}
}
}
iterate(collection, function(object, key) {
accumulator = iteratee.call(thisVal, accumulator, object, key);
});
return accumulator;
}
extend(H, {
pluck: pluck,
each: iterate,
map: map,
invoke: invoke
invoke: invoke,
reduce: reduce
});
function arity(fn, n) {

View File

@ -212,6 +212,45 @@ describe("Helpers", function() {
});
});
describe("#reduce", function() {
var arr = [1, 2, 3, 4, 5, 6],
obj = { a: 1, b: 2 };
function add(sum, n) { return sum + n; }
it("reduces over a collection with the provided iteratee", function() {
expect(_.reduce(arr, add, 0)).to.be.eql(21);
expect(_.reduce(obj, add, 0)).to.be.eql(3);
});
it("defaults to the first value for the accumulator", function() {
var obj = {
a: { name: "hello" },
b: { name: "world" }
};
expect(_.reduce(arr, add)).to.be.eql(21);
expect(
_.reduce(obj, function(acc, val) {
acc.name += " " + val.name;
return acc;
})
).to.be.eql({ name: "hello world"});
});
it("supports providing a `this` value", function() {
var self = {
toString: function(y) { return y.toString(); }
};
var fn = function(acc, val) {
return acc + this.toString(val);
};
expect(_.reduce(arr, fn, 1, self)).to.be.eql("123456");
});
});
describe("#arity", function() {
it("creates a function that only takes a certain # of args", function() {
var fn = spy();