diff --git a/index.html b/index.html index ebbf82dbc..9850daf9d 100644 --- a/index.html +++ b/index.html @@ -123,10 +123,14 @@ Collections
each, map, - reduce, detect, select, reject, all, - any, include, invoke, pluck, max, - min, sortBy, sortedIndex, toArray, - size + reduce, reduceRight, + detect, select, + reject, all, + any, include, + invoke, pluck, + max, min, + sortBy, sortedIndex, + toArray, size

@@ -195,7 +199,7 @@ _.map([1, 2, 3], function(num){ return num * 3 });

reduce_.reduce(list, memo, iterator, [context]) - Alias: inject + Aliases: inject, foldl
Also known as inject and foldl, reduce boils down a list of values into a single value. Memo is the initial state @@ -205,6 +209,19 @@ _.map([1, 2, 3], function(num){ return num * 3 });

 var sum = _.reduce([1, 2, 3], 0, function(memo, num){ return memo + num });
 => 6
+
+ +

+ reduceRight_.reduceRight(list, memo, iterator, [context]) + Alias: foldr +
+ The right-associative version of reduce. Delegates to the + JavaScript 1.8 version of reduceRight, if it exists. +

+
+var list = [[0, 1], [2, 3], [4, 5]];
+var flat = _.reduceRight(list, [], function(a, b) { return a.concat(b); });
+=> [4, 5, 2, 3, 0, 1]
 

diff --git a/test/collections.js b/test/collections.js index 3ef2ccba3..a55d02e88 100644 --- a/test/collections.js +++ b/test/collections.js @@ -47,10 +47,19 @@ $(document).ready(function() { var sum = _.reduce([1, 2, 3], 0, function(sum, num){ return sum + num; }); equals(sum, 6, 'can sum up an array'); + var context = {multiplier : 3}; + sum = _.reduce([1, 2, 3], 0, function(sum, num){ return sum + num * this.multiplier; }, context); + equals(sum, 18, 'can reduce with a context object'); + sum = _.inject([1, 2, 3], 0, function(sum, num){ return sum + num; }); equals(sum, 6, 'aliased as "inject"'); }); + test('collections: reduceRight', function() { + var list = _.foldr([1, 2, 3], '', function(memo, num){ return memo + num; }); + equals(list, '321', 'can perform right folds'); + }); + test('collections: detect', function() { var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; }); equals(result, 2, 'found the first "2" and broke the loop'); diff --git a/underscore.js b/underscore.js index fee281f8d..9b2dfb84b 100644 --- a/underscore.js +++ b/underscore.js @@ -61,14 +61,26 @@ }; // Reduce builds up a single result from a list of values. Also known as - // inject, or foldl. + // inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible. _.reduce = function(obj, memo, iterator, context) { + if (obj && obj.reduce) return obj.reduce(_.bind(iterator, context), memo); _.each(obj, function(value, index, list) { memo = iterator.call(context, memo, value, index, list); }); return memo; }; + // The right-associative version of reduce, also known as foldr. Uses + // JavaScript 1.8's version of reduceRight, if available. + _.reduceRight = function(obj, memo, iterator, context) { + if (obj && obj.reduceRight) return obj.reduceRight(_.bind(iterator, context), memo); + var reversed = _.clone(_.toArray(obj)).reverse(); + _.each(reversed, function(value, index) { + memo = iterator.call(context, memo, value, index, obj); + }); + return memo; + }; + // Return the first value which passes a truth test. _.detect = function(obj, iterator, context) { var result; @@ -368,6 +380,7 @@ // Create a (shallow-cloned) duplicate of an object. _.clone = function(obj) { + if (_.isArray(obj)) return obj.slice(0); return _.extend({}, obj); }; @@ -455,7 +468,8 @@ /*------------------------------- Aliases ----------------------------------*/ _.forEach = _.each; - _.inject = _.reduce; + _.foldl = _.inject = _.reduce; + _.foldr = _.reduceRight; _.filter = _.select; _.every = _.all; _.some = _.any;