Permalink
Browse files

Merge pull request #1669 from megawac/reduceRight

More elegant _.reduce*
  • Loading branch information...
2 parents 9d29dcb + 11284a6 commit e69c63c6e5dabc8556c8fab072cad9fed579477e @jashkenas jashkenas committed Jul 1, 2014
Showing with 29 additions and 25 deletions.
  1. +2 −0 test/collections.js
  2. +27 −25 underscore.js
View
2 test/collections.js
@@ -112,6 +112,7 @@
ok(_.reduce(null, _.noop, 138) === 138, 'handles a null (with initial value) properly');
equal(_.reduce([], _.noop, undefined), undefined, 'undefined can be passed as a special case');
+ equal(_.reduce([_], _.noop), _, 'collection of length one with no initial value returns the first item');
raises(function() { _.reduce([], _.noop); }, TypeError, 'throws an error for empty arrays with no initial value');
raises(function() {_.reduce(null, _.noop);}, TypeError, 'handles a null (without initial value) properly');
@@ -132,6 +133,7 @@
equal(sum, 6, 'default initial value on object');
ok(_.reduceRight(null, _.noop, 138) === 138, 'handles a null (with initial value) properly');
+ equal(_.reduceRight([_], _.noop), _, 'collection of length one with no initial value returns the first item');
equal(_.reduceRight([], _.noop, undefined), undefined, 'undefined can be passed as a special case');
View
52 underscore.js
@@ -131,41 +131,43 @@
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`.
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
if (obj == null) obj = [];
iterator = createCallback(iterator, context, 4);
- _.each(obj, function(value, index, list) {
- if (!initial) {
- memo = value;
- initial = true;
- } else {
- memo = iterator(memo, value, index, list);
- }
- });
- if (!initial) throw TypeError(reduceError);
+ var index = 0, length = obj.length,
+ currentKey, keys;
+ if (length !== +length) {
+ keys = _.keys(obj);
+ length = keys.length;
+ }
+ if (arguments.length < 3) {
+ if (!length) throw TypeError(reduceError);
+ memo = obj[keys ? keys[index++] : index++];
+ }
+ for (; index < length; index++) {
+ currentKey = keys ? keys[index] : index;
+ memo = iterator(memo, obj[currentKey], currentKey, obj);
+ }
return memo;
};
// The right-associative version of reduce, also known as `foldr`.
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
if (obj == null) obj = [];
- var length = obj.length;
iterator = createCallback(iterator, context, 4);
- if (length !== +length) {
- var keys = _.keys(obj);
- length = keys.length;
+ var index = obj.length,
+ currentKey, keys;
+ if (index !== +index) {
+ keys = _.keys(obj);
+ index = keys.length;
+ }
+ if (arguments.length < 3) {
+ if (!index) throw TypeError(reduceError);
+ memo = obj[keys ? keys[--index] : --index];
+ }
+ while (index--) {
+ currentKey = keys ? keys[index] : index;
+ memo = iterator(memo, obj[currentKey], currentKey, obj);
}
- _.each(obj, function(value, index, list) {
- index = keys ? keys[--length] : --length;
- if (!initial) {
- memo = obj[index];
- initial = true;
- } else {
- memo = iterator(memo, obj[index], index, list);
- }
- });
- if (!initial) throw TypeError(reduceError);
return memo;
};

0 comments on commit e69c63c

Please sign in to comment.