Skip to content

Commit

Permalink
Fix d3#2031 - Create a map from an array.
Browse files Browse the repository at this point in the history
The d3.map constructor can now be used to index the elements of an array by an
optional key function, providing a convenient (and faster) alternative to using
d3.nest. Before:

  var objectByKey = d3.nest()
      .key(function(d) { return d.key; })
      .rollup(function(values) { return values[0]; })
      .map(objects, d3.map);

After:

  var objectByKey = d3.map(objects, function(d) { return d.key; });

Note that the behavior of the d3.map constructor now changes slightly when a
sparse array is used. Previously, missing elements from sparse arrays were
skipped by the for-in loop, but now missing elements are indexed.
  • Loading branch information
mbostock committed Oct 24, 2014
1 parent 9364923 commit 9bb8561
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 10 deletions.
15 changes: 11 additions & 4 deletions d3.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,18 @@
});
}
}
d3.map = function(object) {
d3.map = function(object, f) {
var map = new d3_Map();
if (object instanceof d3_Map) object.forEach(function(key, value) {
map.set(key, value);
}); else for (var key in object) map.set(key, object[key]);
if (object instanceof d3_Map) {
object.forEach(function(key, value) {
map.set(key, value);
});
} else if (Array.isArray(object)) {
var i = -1, n = object.length, o;
if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o);
} else {
for (var key in object) map.set(key, object[key]);
}
return map;
};
function d3_Map() {
Expand Down
6 changes: 3 additions & 3 deletions d3.min.js

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions src/arrays/map.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import "../core/class";

d3.map = function(object) {
d3.map = function(object, f) {
var map = new d3_Map;
if (object instanceof d3_Map) object.forEach(function(key, value) { map.set(key, value); });
else for (var key in object) map.set(key, object[key]);
if (object instanceof d3_Map) {
object.forEach(function(key, value) { map.set(key, value); });
} else if (Array.isArray(object)) {
var i = -1,
n = object.length,
o;
if (arguments.length === 1) while (++i < n) map.set(i, object[i]);
else while (++i < n) map.set(f.call(object, o = object[i], i), o);
} else {
for (var key in object) map.set(key, object[key]);
}
return map;
};

Expand Down
11 changes: 11 additions & 0 deletions test/arrays/map-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ suite.addBatch({
assert.equal(b.get("foo"), 42);
a.set("bar", true);
assert.isFalse(b.has("bar"));
},
"map(array) creates a map by index": function(map) {
assert.deepEqual(map(["foo", "bar"]).entries(), [{key: "0", value: "foo"}, {key: "1", value: "bar"}]);
},
"map(array) indexes missing elements in sparse arrays": function(map) {
assert.deepEqual(map(["foo", , "bar"]).entries(), [{key: "0", value: "foo"}, {key: "1", value: undefined}, {key: "2", value: "bar"}]);
},
"map(array, f) creates a map by accessor": function(map) {
assert.deepEqual(map([{field: "foo"}, {field: "bar"}], function(d) { return d.field; }).entries(), [{key: "foo", value: {field: "foo"}}, {key: "bar", value: {field: "bar"}}]);
assert.deepEqual(map([{field: "foo"}, {field: "bar"}], function(d, i) { return i; }).entries(), [{key: "0", value: {field: "foo"}}, {key: "1", value: {field: "bar"}}]);
assert.deepEqual(map([{field: "foo"}, {field: "bar"}], function(d, i) { return this[i].field; }).entries(), [{key: "foo", value: {field: "foo"}}, {key: "bar", value: {field: "bar"}}]);
}
},
"size": {
Expand Down

0 comments on commit 9bb8561

Please sign in to comment.