{{ message }}

Instantly share code, notes, and snippets.

Last active Dec 11, 2015
Underscore.js equivalents in D3

## Collections

### each(array)

Underscore example:

`_.each([1, 2, 3], function(num) { alert(num); });`

Vanilla equivalent:

`[1, 2, 3].forEach(function(num) { alert(num); });`

### each(object)

Underscore example:

`_.each({one: 1, two: 2, three: 3}, function(num, key) { alert(num); });`

D3 equivalent using d3.values (d3.entries and d3.map forEach would also work):

`d3.values({one: 1, two: 2, three: 3}).forEach(function(num) { alert(num); });`

### map(array)

Underscore example:

`_.map([1, 2, 3], function(num) { return num * 3; });`

Vanilla equivalent:

`[1, 2, 3].map(function(num) { return num * 3; });`

### map(object)

Underscore example:

`_.map({one: 1, two: 2, three: 3}, function(num, key) { return num * 3; });`

D3 equivalent with d3.values (d3.entries and d3.map values.map would also work):

`d3.values({one: 1, two: 2, three: 3}).map(function(num) { return num * 3; });`

### reduce

Underscore example:

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

Vanilla equivalent:

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

### reduceRight

Given:

`var list = [[0, 1], [2, 3], [4, 5]];`

Underscore example:

`var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);`

Vanilla equivalent:

`var flat = list.reduceRight(function(a, b) { return a.concat(b); }, []);`

### find

Underscore example:

`var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });`

There’s no proper Vanilla equivalent of Underscore’s find method, but you can approximate it with array.filter. This is typically slower because it doesn’t stop once the first match is found:

`var even = [1, 2, 3, 4, 5, 6].filter(function(num) { return num % 2 == 0; })[0];`

A closer approximate is array.some, but this is less convenient because it requires the closure to set an enclosing variable:

`var even; [1, 2, 3, 4, 5, 6].some(function(num) { return num % 2 == 0 && (even = num, true); });`

### contains

Underscore example:

`_.contains([1, 2, 3], 3);`

Vanilla equivalent:

`[1, 2, 3].indexOf(3) >= 0;`

### invoke

Underscore example:

`_.invoke([[5, 1, 7], [3, 2, 1]], "sort"]);`

Vanilla equivalent:

`[[5, 1, 7], [3, 2, 1]].forEach(function(array) { array.sort(); });`

Note: JavaScript’s built-in array.sort sorts lexicographically rather than numerically; you almost always want to say `array.sort(d3.ascending)`, or `array.sort(function(a, b) { return a - b; })` if you know you’re sorting numbers or dates.

### pluck

Given:

`var stooges = [{name: "moe", age: 40}, {name: "larry", age: 50}, {name: "curly", age: 60}];`

Underscore example:

`_.pluck(stooges, "name");`

Vanilla equivalent:

`stooges.map(function(stooge) { return stooge.name; });`

### max

Given:

`var stooges = [{name: "moe", age: 40}, {name: "larry", age: 50}, {name: "curly", age: 60}];`

Underscore example:

`_.max(stooges, function(stooge) { return stooge.age; });`

Vanilla equivalent. You can omit the null argument if you know that stooges is non-empty or you’d prefer a TypeError:

`stooges.reduce(function(p, v) { return v.age > p.age ? v : p; }, null);`

Using d3.max is not exactly equivalent because it returns the maximum value, rather than the corresponding object. Also, d3.max ignores null, undefined and NaN values. Often, this is what you want:

`d3.max(stooges, function(stooge) { return stooge.age; });`

### min

Given:

`var numbers = [10, 5, 100, 2, 1000];`

Underscore example:

`_.min(numbers);`

Vanilla equivalent:

`numbers.reduce(function(p, v) { return Math.min(p, v); }, Infinity);`

Using d3.min (not equivalent; see above regarding d3.max):

`d3.min(numbers);`

### sortBy

Underscore example:

`_.sortBy([1, 2, 3, 4, 5, 6], function(num) { return Math.sin(num); });`

Vanilla equivalent:

`[1, 2, 3, 4, 5, 6].sort(function(a, b) { return Math.sin(a) - Math.sin(b); });`

In the vanilla equivalent, the comparator is invoked once per comparison rather than once per element; thus the vanilla version is potentially slower. More critically, array.sort doesn’t support nondeterministic comparators. You could fix that with a temporary array holding the mapped values, a second temporary array holding the indexes, and d3.permute:

```var array = [1, 2, 3, 4, 5, 6], sin = array.map(Math.sin);
d3.permute(array, d3.range(array.length).sort(function(i, j) { return sin[i] - sin[j]; }));```

### groupBy

Underscore example:

`_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });`

D3 equivalent:

`d3.nest().key(Math.floor).map([1.3, 2.1, 2.4]);`

Underscore example:

`_.groupBy(["one", "two", "three"], "length");`

D3 equivalent:

`d3.nest().key(function(d) { return d.length; }).map(["one", "two", "three"]);`

D3’s nest operator supports more than one level of grouping, and can also return nested entries that preserve order.

### countBy

Underscore example:

```_.countBy([1, 2, 3, 4, 5], function(num) {
return num % 2 == 0 ? "even" : "odd";
});```

D3 equivalent using nest.rollup:

```d3.nest()
.key(function(num) { return num % 2 == 0 ? "even" : "odd"; })
.rollup(function(values) { return values.length; })
.map([1, 2, 3, 4, 5]);```

### shuffle

Underscore example:

`_.shuffle([1, 2, 3, 4, 5, 6]);`

D3 equivalent:

`d3.shuffle([1, 2, 3, 4, 5, 6]);`

### toArray

Underscore example:

`(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);`

Vanilla equivalent:

`(function(){ return [].slice.call(arguments, 1); })(1, 2, 3, 4);`

### size

Underscore example:

`_.size({one: 1, two: 2, three: 3});`

D3 equivalent using d3.keys:

`d3.keys({one: 1, two: 2, three: 3}).length;`

D3 equivalent using d3.map, if you want to perform other operations:

`d3.map({one: 1, two: 2, three: 3}).keys().length;`

## Array Functions

This is still a work in-progress.