Skip to content

Commit

Permalink
adding a reduceRight (it's in JS 1.8), and aliasing foldl and foldr
Browse files Browse the repository at this point in the history
  • Loading branch information
jashkenas committed Oct 30, 2009
1 parent eca085a commit cb38c6a
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
27 changes: 22 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,14 @@ <h2>Table of Contents</h2>
<b>Collections</b>
<br />
<span class="methods"><a href="#each">each</a>, <a href="#map">map</a>,
<a href="#reduce">reduce</a>, <a href="#detect">detect</a>, <a href="#select">select</a>, <a href="#reject">reject</a>, <a href="#all">all</a>,
<a href="#any">any</a>, <a href="#include">include</a>, <a href="#invoke">invoke</a>, <a href="#pluck">pluck</a>, <a href="#max">max</a>,
<a href="#min">min</a>, <a href="#sortBy">sortBy</a>, <a href="#sortedIndex">sortedIndex</a>, <a href="#toArray">toArray</a>,
<a href="#size">size</a></span>
<a href="#reduce">reduce</a>, <a href="#reduceRight">reduceRight</a>,
<a href="#detect">detect</a>, <a href="#select">select</a>,
<a href="#reject">reject</a>, <a href="#all">all</a>,
<a href="#any">any</a>, <a href="#include">include</a>,
<a href="#invoke">invoke</a>, <a href="#pluck">pluck</a>,
<a href="#max">max</a>, <a href="#min">min</a>,
<a href="#sortBy">sortBy</a>, <a href="#sortedIndex">sortedIndex</a>,
<a href="#toArray">toArray</a>, <a href="#size">size</a></span>
</p>

<p>
Expand Down Expand Up @@ -195,7 +199,7 @@ <h2>Collection Functions (Arrays or Objects)</h2>

<p id="reduce">
<b class="header">reduce</b><code>_.reduce(list, memo, iterator, [context])</code>
<span class="alias">Alias: <b>inject</b></span>
<span class="alias">Aliases: <b>inject, foldl</b></span>
<br />
Also known as <b>inject</b> and <b>foldl</b>, <b>reduce</b> boils down a
<b>list</b> of values into a single value. <b>Memo</b> is the initial state
Expand All @@ -205,6 +209,19 @@ <h2>Collection Functions (Arrays or Objects)</h2>
<pre>
var sum = _.reduce([1, 2, 3], 0, function(memo, num){ return memo + num });
=&gt; 6
</pre>

<p id="reduceRight">
<b class="header">reduceRight</b><code>_.reduceRight(list, memo, iterator, [context])</code>
<span class="alias">Alias: <b>foldr</b></span>
<br />
The right-associative version of <b>reduce</b>. Delegates to the
JavaScript 1.8 version of <b>reduceRight</b>, if it exists.
</p>
<pre>
var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, [], function(a, b) { return a.concat(b); });
=&gt; [4, 5, 2, 3, 0, 1]
</pre>

<p id="detect">
Expand Down
9 changes: 9 additions & 0 deletions test/collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
18 changes: 16 additions & 2 deletions underscore.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
};

Expand Down Expand Up @@ -455,7 +468,8 @@
/*------------------------------- Aliases ----------------------------------*/

_.forEach = _.each;
_.inject = _.reduce;
_.foldl = _.inject = _.reduce;
_.foldr = _.reduceRight;
_.filter = _.select;
_.every = _.all;
_.some = _.any;
Expand Down

0 comments on commit cb38c6a

Please sign in to comment.