12
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

サンプルで確認するD3の配列メソッド

Last updated at Posted at 2015-07-17

D3.js には便利な関数がたくさんある感じなんですけど、 英語のページ をみてもよく分からんし 日本語の解説ページ を見ても難しくて分からん。ってことで、サンプル動かして動作を確認してみましたよ。

やっぱりデータ見たほうがわかりやすいですね。

全体的な感じからすると、Undefined を許容したりしなかったりソートされてることが前提って関数が多いんで、配列操作のときは事前にソートと値なしの排除をしとくのが確かっぽいですね。
ちなみに Array.sort() だと辞書順にならんでしまいますので、 d3.ascending() を使うのが確実です。

よく使いそうな関数には☆をつけて、ハマリポイントがありそうな関数には注釈のコメント入れてます。

D3: ARRAY METHODS

Ordering

d3.ascending(a, b) ☆

var a = 10,
    b = 1;
p(d3.ascending(a, b)); // return: 1
var c = undefined;
p(d3.ascending(a, c)); // return: NaN
var d = "-";
p(d3.ascending(a, d)); // return: NaN

d3.descending(a, b) ☆

var a = 10,
    b = 2;
p(d3.descending(a, b)); // return: -1

d3.min(array[, accessor])

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.min(a)); // return: 0
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.min(a, function(d, i) {
  return parseInt(d) + 1;
})); // return: 1

d3.max(array[, accessor])

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.max(a)); // return: 10
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.max(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 14

d3.extent(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.extent(a)); // return: 0,10
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.extent(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 0,14

d3.sum(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.sum(a)); // return: 15
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.sum(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 28

d3.mean(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.mean(a)); // return: 3
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.mean(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 5.6

d3.median(array[, accessor]) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.median(a)); // return: 2
var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.median(a, function(d, i) {
  return parseInt(d) + i;
})); // return: 5

d3.quantile(numbers, p)

var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                        // return: ["0",1,10,"2",2,null]
p(d3.quantile(a, 0.5));      // return: 6
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                        // return: ["0",1,"2",2,10,null]
p(d3.quantile(a, 0.5));      // return: 2
var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                        // return: ["0",1,10,"2",2,null]
p(d3.quantile(a, 0.75));     // return: 2
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                        // return: ["0",1,"2",2,10,null]
p(d3.quantile(a, 0.75));     // return: 8

d3.bisecLeft(array, x[, lo[, hi]])

var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                         // return: ["0",1,10,"2",2,null]
p(d3.bisectLeft(a, 3));       // return: 5
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                         // return: ["0",1,"2",2,10,null]
p(d3.bisectLeft(a, 3));       // return: 4
p(d3.bisectLeft(a, 3, 2, 3)); // return: 3

d3.bisect(array, x[, lo[, hi]]), d3.bisectRight(array, x[, lo[, hi]])

右側(後ろ)から調べてるようで配列の最後に Undefined があると期待した値が返ってきません。

var a = ["0", 1, undefined, 2, 10, "2"];
a.sort();
p(a);                              // return: ["0",1,10,"2",2,null]
p(d3.bisect(a, 3));                // return: 6
p(d3.bisectRight(a, 3));           // return: 6
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                              // return: ["0",1,"2",2,10,null]
p(d3.bisect(a, 3));                // return: 6
p(d3.bisectRight(a, 3));           // return: 6
p(d3.bisect(a, 2));                // return: 6
p(d3.bisectRight(a, 2));           // return: 6
var b = a.filter(function(d, i) {
  return d != undefined;
});
p(b);                              // return: ["0",1,"2",2,10]
p(d3.bisect(b, 2));                // return: 4
p(d3.bisectRight(b, 2));           // return: 4
p(d3.bisect(b, 1));                // return: 2
p(d3.bisectRight(b, 1));           // return: 2
p(d3.bisect(b, 1, 3, 4));          // return: 3
p(d3.bisectRight(b, 1, 3, 4));     // return: 3

d3.bisector(accessor)

右側(後ろ)から調べてるようで配列の最後に Undefined があると期待した値が返ってきません。

var bisect = d3.bisector(function(d) { return d; }).right;
var bisectLeft = d3.bisector(function(d) { return d; }).left;
var a = ["0", 1, undefined, 2, 10, "2"];
p(a);                             // return: ["0",1,null,2,10,"2"]
p(bisect(a, 2));                  // return: 6
a.sort();
p(a);                             // return: ["0",1,10,"2",2,null]
p(bisect(a, 2));                  // return: 6
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
p(a);                             // return: ["0",1,"2",2,10,null]
p(bisect(a, 2));                  // return: 6
var b = a.filter(function(d, i) {
  return d != undefined;
});
p(b);                             // return: ["0",1,"2",2,10]
p(bisect(b, 2));                  // return: 4
p(bisectLeft(b, 2));              // return: 2
p(bisect(b, 3));                  // return: 4
p(bisectLeft(b, 3));              // return: 4

d3.bisector(comparator)

右側(後ろ)から調べてるようで配列の最後に Undefined があると期待した値が返ってきません。

var bisect = d3.bisector(function(d) { return d; }).right;
var bisectComparator = d3.bisector(function(a, b) { return b - a; }).right;
var a = ["0", 1, undefined, 2, 10, "2"];
a.sort(function(a, b) {
  return d3.ascending(a, b);
});
var b = a.filter(function(d, i) {
  return d != undefined;
});
p(b);                      // return: ["0",1,"2",2,10]
p(bisect(b, 2));           // return: 4
p(bisectComparator(b, 2)); // return: 5

d3.shuffle(array)

var a = ["0", 1, undefined, 2, 10, "2"];
p(d3.shuffle(a)); // return: ["0",1,"2",10,null,2]
p(d3.shuffle(a)); // return: [null,1,10,"2",2,"0"]
p(d3.shuffle(a)); // return: [null,2,"2",10,"0",1]

Associative Arrays

d3.keys(object)

var o = {
  b: 54,
  a: 30,
  c: 12
};
p(o);          // return: return: {"b":54,"a":30,"c":12}
p(d3.keys(o)); // return: ["b","a","c"]

d3.values(object)

var o = {
  b: 54,
  a: 30,
  c: 12
};
p(o);            // return: return: {"b":54,"a":30,"c":12}
p(d3.values(o)); // return: [54,30,12]

d3.entries(object)

var o = {
  b: [54, 34, 89],
  a: [30, 34, 59],
  c: [30, 12, 12]
};
p(o);             // return: {"b":[54,34,89],"a":[30,34,59],"c":[30,12,12]}
p(d3.entries(o)); // return: [{"key":"b","value":[54,34,89]},{"key":"a","value":[30,34,59]},{"key":"c","value":[30,12,12]}]

Maps

d3.map([object[, key])

キーを指定しないと数字の添字になってしまいますので、キーを指定する関数は必ず入れたほうがいいでしょう。
また、重複した要素があるときにキーを指定した時としない時では結果が違います。

var o = d3.map([{name: "foo"}, {name: "bar"}]);
p(o); // {"_":{"0":{"name":"foo"},"1":{"name":"bar"}}}
var m = d3.map([{name: "foo"}, {name: "bar"}, {name: "bar"}]);
p(m); // {"_":{"0":{"name":"foo"},"1":{"name":"bar"},"2":{"name":"bar"}}}
    m = d3.map([{name: "foo"}, {name: "bar"}, {name: "bar"}], function(d) { return d.name; });
p(m); // {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}

map.has(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);            // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.has("foo")); // return: true
p(m.has("baz")); // return: false

map.get(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);            // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.get("foo")); // return: {"name":"foo"}
p(m.get("baz")); // return: undefined

map.set(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m); // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
m.set("foo", {"name": "test"});
m.set("baz", {"name": "foo"});
p(m); // return: {"_":{"foo":{"name":"test"},"bar":{"name":"bar"},"baz":{"name":"foo"}}}

map.remove(key)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m); // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
m.remove("foo");
p(m); // return: {"_":{"bar":{"name":"bar"}}}

map.keys()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);        // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.keys()); // return: ["foo","bar"]

map.values()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);          // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.values()); // return: [{"name":"foo"},{"name":"bar"}]

map.entries()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);           // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.entries()); // return: [{"key":"foo","value":{"name":"foo"}},{"key":"bar","value":{"name":"bar"}}]

map.forEach(function)

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);        // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
m.forEach(function(k, v) {
  p([k, v]); // return: ["foo",{"name":"foo"}], return: ["bar",{"name":"bar"}]
});

map.empty()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);                  // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.empty());          // return: false
p(d3.map([]).empty()); // return: true

map.size()

var m = d3.map([{name: "foo"}, {name: "bar"}], function(d) { return d.name; });
p(m);                 // return: {"_":{"foo":{"name":"foo"},"bar":{"name":"bar"}}}
p(m.size());          // return: 2
p(d3.map([]).size()); // return: 0

Sets

d3.set([array]) ☆

配列の深さが違う場合にもゴニョゴニョしてくれる感じですけど、カンマ区切りの値になってしまうようです。

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a); // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
var a = d3.set([["foo"], ["bar", "baz"]]);
p(a);     // return: {"_":{"foo":true,"bar,baz":true}}

set.has(value)

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);        // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.has(2)); // return: true
p(a.has(3)); // return: false

set.add(value) ☆

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);     // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
a.add(5);
p(a);     // return: {"_":{"0":true,"1":true,"2":true,"5":true,"10":true,"undefined":true}}

set.remove(value)

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);     // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
a.remove(1);
p(a);     // return: {"_":{"0":true,"2":true,"10":true,"undefined":true}}

set.values() ☆

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);          // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.values()); // return: ["0","1","2","10","undefined"]

set.forEach(function)

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);          // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
a.forEach(function(v) {
    p(v); // return: "0", return: "1", return: "2", return: "10", return: "undefined"
});

set.empty()

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);                  // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.empty());          // return: false
p(d3.set([]).empty()); // return: true

set.size()

var a = d3.set(["0", 1, undefined, 2, 10, "2"]);
p(a);                 // return: {"_":{"0":true,"1":true,"2":true,"10":true,"undefined":true}}
p(a.size());          // return: 5
p(d3.set([]).size()); // return: 0

Array Operators

d3.merge(arrays)

var a = d3.merge([ [1], [2, 3] ]);
p(a); // return: [1,2,3]
var a = d3.merge([ [1], [2, 3], [5, [2,3]] ]);
p(a); // return: [1,2,3,5,[2,3]]

d3.range([start, ]stop[, step]) ☆

start <= range < stop という関係のようですのでちょっと注意が必要です。

var a = d3.range(5);
p(a);                     // return: [0,1,2,3,4]
p(d3.range(10, 100, 10)); // return: [10,20,30,40,50,60,70,80,90]

d3.permute(array, indexes) ☆

var a = ["0", 1, undefined, 2, 10, "2"];
p(a);                        // return: ["0", 1, undefined, 2, 10, "2"]
p(d3.permute(a, [2, 5, 1])); // return: [null,"2",1]
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
p(a);                             // return: [0,1,2,3,4,5,6,7,8,9]
p(d3.permute(a, d3.range(3, 6))); // return: [3,4,5]

d3.zip(arrays...) ☆

要素数が足りない場合は配列が作成されない模様。

var a = d3.zip(["a", "b"], [1, 6], [2, 7], [3, 8]);
p(a); // return: [["a",1,2,3],["b",6,7,8]]
var a = d3.zip(["a", "b"], [1, 6, 10], [2, 7], [3, 8]);
p(a); // return: [["a",1,2,3],["b",6,7,8]]
var a = d3.zip(["a", "b", "c"], [1, 6], [2, 7], [3, 8]);
p(a); // return: [["a",1,2,3],["b",6,7,8]]

d3.transpose(matrix)

var a = d3.transpose([["a", 1, 11], ["b", 2, 12], ["c", 3, 13]]);
p(a); // return: [["a","b","c"],[1,2,3],[11,12,13]]

d3.d3.pairs(array)

var a = d3.pairs(["0", 1, undefined, 2, 10, "2"]);
p(a); // return: [["0",1],[1,null],[null,2],[2,10],[10,"2"]]

Nest

d3.nest()

var n = d3.nest();
p(n); // return: {}

nest.entries(array)

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .entries(o);
p(n); // return: [{"key":"foo","val":10},{"key":"bar","val":30},{"key":"baz","val":20}]

nest.key(function)

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "bar", "val": 15},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .entries(o);
p(n); // return: [{"key":"foo","values":[{"key":"foo","val":10}]},{"key":"bar","values":[{"key":"bar","val":30},{"key":"bar","val":15}]},{"key":"baz","values":[{"key":"baz","val":20}]}]

nest.sortKeys(comparator) ☆

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .sortKeys(d3.ascending)
          .entries(o);
p(n); // return: [{"key":"bar","values":[{"key":"bar","val":30}]},{"key":"baz","values":[{"key":"baz","val":20}]},{"key":"foo","values":[{"key":"foo","val":10}]}]

nest.sortValues(comparator)

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "bar", "val": 15},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .sortValues(function(a, b) {p([a, b]); return d3.ascending(a.val, b.val);})
          .entries(o);
p(n); // return: [{"key":"foo","values":[{"key":"foo","val":10}]},{"key":"bar","values":[{"key":"bar","val":15},{"key":"bar","val":30}]},{"key":"baz","values":[{"key":"baz","val":20}]}]

nest.rollup(function) ☆

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "bar", "val": 15},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .sortKeys(d3.ascending)
          .rollup(function(d) {
            var val = 0;
            d.forEach(function(v) {
              val += v.val;
            });
            return val;
          })
          .entries(o);
p(n); // return: [{"key":"bar","values":45},{"key":"baz","values":20},{"key":"foo","values":10}]

nest.map(array[, mapType])

var o = [
  {"key": "foo", "val": 10},
  {"key": "bar", "val": 30},
  {"key": "baz", "val": 20}
];
var n = d3.nest()
          .key(function(d) {return d.key; })
          .map(o, d3.map);
p(n); // return: {"_":{"foo":[{"key":"foo","val":10}],"bar":[{"key":"bar","val":30}],"baz":[{"key":"baz","val":20}]}}
12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?