Underscore.js Avails Interesting Possibilities with Reduce

Since I began playing around with Underscore.js, I have become obsessed with its reduce method. reduce takes a collection (or an object) and returns a single value. But it is the way in which it does that which makes it compelling. From the documentation, its signature is:

_.reduce(list, iterator, memo, [context])

I’ll start out with a simple example. Probably the kind of example you’ll see everywhere around the Internet:

var result = _.reduce([100, 25, 2], function(memo, num) {
	 return memo / num;
});
// result === 2

The iterator function is being applied to each of the elements of the list. But not only that, it is making available to each iteration the result of the previous iterator-function’s result.

  • In the first iteration, memo has the value 100 and num is 25.
  • In the second iteration, memo has the value 4 and num is 2.

As you can see, the value of memo in the second iteration is equal to the result of the iterator function from the first iteration. So we have this concept of a value which is travelling through the iterations. The parameter memo is short for memoization. This is an implementation detail which is not relevant to this post. As that parameter travels from function to function through the iterations, I am using the name traveller for the purposes of this post.

There are only 2 iterations in this example because the list has 3 items and we have not passed it a seed value as the 3rd possible parameter. If we change that function to the following, we will get 3 iterations and the value of traveller on the 1st iteration will be 10000, whilst the value of num will be 100.

var result = _.reduce([100, 25, 2], function(traveller, num) {
	 return traveller / num;
}, 10000);
// result === 2

When it comes to the iterator function, you are free to be very creative in there. But first, I just want to point out that it is not limited to integers. The following example creates a sentence out of a string array:

var words = ['Reduce', 'is', 'an', 'interesting', 'method'];

var sentence = _.reduce(words, function(traveller, current) {
	var collate = traveller + ' ' + current;
	return collate;
});
//	sentence === 'Reduce is an interesting method'

You can also pass an object as the first parameter. This is where you can do some interesting stuff, like the following example that creates an address object from a person object:

var person = {
	name: 'Dave',
	age: 39,
	address: '28 Scenic Road',
	suburb: 'Kenmore',
	postcode: 4069
};

var address = _.reduce(person, function(traveller, objectValue, objectMember) {
    switch (objectMember) {
		case 'address':
		case 'suburb':
		case 'postcode':
			traveller[objectMember] = objectValue; break;
		default : break;
    }
    return traveller;
}, {});

You can see that I have passed an empty object as the 3rd parameter to reduce, which will be the initial value of the traveller parameter.

Note that I’m not saying the last example is the best way to achieve that end. But that example does show that you can use the reduce function for a great many things beyond simple arithmetic and sentence construction.

Perhaps in a month or 2 I’ll have a really good example that solves a problem nice and elegantly.

Until then!

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>