当前位置: 首页 > 文档资料 > D3.js 帮助文档 >

d3-collection

优质
小牛编辑
129浏览
2023-12-01

几种常用的键值对类型的数据结构

Installing

NPM 安装:npm install d3-collection, 还可以下载最新版,此外还可以直接从 d3js.org单独的标准库 或作为 D3 4.0 的一部分引入,支持 AMD, CommonJS 以及 vanilla 环境, 使用标签引入会暴露 d3 全局变量:

<script src="https://d3js.org/d3-collection.v1.min.js"></script>
<script>

var map = d3.map()
    .set("foo", 1)
    .set("bar", 2);

</script>

在浏览器中测试 d3-collection

API Reference

  • Objects

    在JavaScript中常见的数据类型是 associative array(关联数组), 简言之就是具有一个属性集的 对象. 对象的的标准迭代方式是 for…in 循环, 但是迭代次序是未定义的. D3 提供了几种将对象转为数字索引的标准数组的方法.

    请注意:当使用普通对象作为属性名是可以的,但是当使用特殊内置的属性名时会导致意想不到的事发生,比如使用 object["__proto__"] = 42"hasOwnProperty" in object. 如果不能保证映射的键是安全的情况下请使用 maps 和 sets(或标准的ES6数据结构)来代替对象.

    d3.keys(object) <源码>

    返回一个包含了指定对象属性名的数组. 数组的顺序是未定义(不可靠)的.

    d3.values(object) <源码>

    返回一个包含了指定对象属性值的数组. 数组的顺序是未定义(不可靠)的.

    d3.entries(object) <源码>

    将对象转为标准的包含 keyvalue 的对象数组.也就是将对象的 key-value 对重组为一个对象, 比如将 {foo: 42} 转为 {key: "foo", value: 42}. 所传入的对象被重组为一个数组. 次序同样是不固定的:

    d3.entries({foo: 42, bar: true}); // [{key: "foo", value: 42}, {key: "bar", value: true}]
    

    Maps

    ES6 Maps 类似, 但是有以下几点不同:

    • d3.mapsKeys 会被强制转为字符串.
    • 使用 map.each 遍历, 而不是 map.forEach. (并且没有 thisArg 参数.)
    • 使用 map.remove, 而不是 map.delete.
    • map.entries 返回 {key, value} 对象数组而不是 [key, value] 迭代器.
    • map.size 是一个方法而不是 property; map.empty 同样也是方法不是属性.

    d3.map([object[, key]]) <源码>

    构建一个新的 map. 如果指定了 object 则将其所有的可枚举对象复制到 map 中. object 可以是一个数组也可以是其他的 map 对象.可选的 key 方法用来指定使用哪个属性作为key, 比如:

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

    参考 nests.

    map.has(key) <源码>

    当且仅当 map 中包含指定的 key 的时候返回 true, 要注意其对应的 value 可能为 null 或者 undefined

    map.get(key) <源码>

    返回指定的 key 对应的值,如果 map 中不包含指定的 key 则返回 undefined

    map.set(key, value) <源码>

    设置 map 中指定的 keyvalue, 如果已经有相同的 key 字符串则会被覆盖,此方法返回 map 对象因此可以链式调用. 例如:

    var map = d3.map()
        .set("foo", 1)
        .set("bar", 2)
        .set("baz", 3);
    
    map.get("foo"); // 1
    

    map.remove(key) <源码>

    如果 map 中包含指定的 key 则将其删除并返回 true, 否则什么都不做并返回 false.

    map.clear() <源码>

    清空 map 中所有的项

    map.keys() <源码>

    以数组的形式返回 map 中所有的 keys, 顺序是不可靠的.

    map.values() <源码>

    以数组的形式返回 map 中所有的 value, 顺序是不可靠的.

    map.entries() <源码>

    map 中所有的项重组为 key-value 数组. 顺序是随意的.每一项中 key 必须是字符串, 但是对应的 value 可以是任意的类型.

    map.each(function) <源码>

    遍历 map 中的每一项, 并对每一项执行 function, 当前项的 valuekey 作为参数, 随后是 map 本身, 返回 undefined.

    map.empty() <源码>

    当且仅当 map 中没有任何项时返回 true.

    map.size() <源码>

    返回 map 中项的个数.

    Sets

    ES6 Sets类似,但是有以下不同:

    • 值会被强制转换为字符串.
    • set.each, 而非 set.forEach. (也没有 thisArg 参数.)
    • set.remove, 而非 set.delete.
    • set.size 是一个方法, 而不是 property; set.empty 也是一个方法而不是属性.

    d3.set([array[, accessor]]) <源码>

    构建一个新的 set 对象. 如果指定了 array 则将 array 中的元素都作为 set 的元素并返回.array 也可以是其他的 set 对象.如果指定了 accessor , 则在将元素添加到 set 之前先对每个元素执行执行的访问器方法.

    set.has(value) <源码>

    set 中包含指定的 value 字符串时返回 true.

    set.add(value) <源码>

    将指定的 value 字符串添加到 set 中并返回 set, 因此支持链式语法:

    var set = d3.set()
        .add("foo")
        .add("bar")
        .add("baz");
    
    set.has("foo"); // true
    

    set.remove(value) <源码>

    如果 set 中存在 value 字符串则将其移除并返回 true, 否则什么都不做并返回 false.

    set.clear() <源码>

    清空 set.

    set.values() <源码>

    以数组的形式返回 set 中所有的 values, 顺序是任意不可信的,可以方便的用来去重:

    d3.set(["foo", "bar", "foo", "baz"]).values(); // "foo", "bar", "baz"
    

    set.each(function) <源码>

    set 中每个元素执行 function, 前两个参数都为 value(为了和 Nests

    Nests(嵌套操作)可以将数组类型的元素重组为层次结构数据。想象一下 SQL 中的 GROUP BY 操作。除了可以对元素进行分组之外,嵌套操作的输出是一个树而不是扁平的表。树的具体结构层级由 key 函数决定。同时可以根据 value 对树的叶节点进行排序,而非叶节点可以根据 key 进行排序. 可选的 rollup 操作可以用来指定对叶节点组进行处理的函数。Nest 操作(由nest返回的对象)是可以多次使用的,并且不保留对嵌套数据的任何引用。

    例如,考虑如下的扁平数据结构:

    var yields = [
      {yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
      {yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca"},
      {yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris"},
      ...
    ];
    

    在可视化时可能需要先根据年份然后按照类别进行分组重构,可以进行如下操作:

    var entries = d3.nest()
        .key(function(d) { return d.year; })
        .key(function(d) { return d.variety; })
        .entries(yields);
    

    返回的结果是一个嵌套的数组,最外层数据都由键值对组成:

    [{key: "1931", values: [
       {key: "Manchuria", values: [
         {yield: 27.00, variety: "Manchuria", year: 1931, site: "University Farm"},
         {yield: 48.87, variety: "Manchuria", year: 1931, site: "Waseca"},
         {yield: 27.43, variety: "Manchuria", year: 1931, site: "Morris"}, ...]},
       {key: "Glabron", values: [
         {yield: 43.07, variety: "Glabron", year: 1931, site: "University Farm"},
         {yield: 55.20, variety: "Glabron", year: 1931, site: "Waseca"}, ...]}, ...]},
     {key: "1932", values: ...}]
    

    嵌套的数据结构能轻松的在 SVGHTML 文档中生成分层结构。

    更多介绍参考:

    d3.nest() <源码>

    构建一个新的嵌套操作。keys 初始为空

    nest.key(key) <源码>

    注册一个新的 key 函数,key 函数将会在输入数组的每个元素上进行调用,并且返回一个字符串标识用来对所有元素进行分组。大多数情况下,是一个简单的访问器,就行上述例子中的年份和种类访问器一样。(key 方法并不传递当前数组的索引),每次注册 key 后,其会被添加到 keys 内部数组的末尾,并且嵌套操作会根据指定的 key 再嵌套一层分组,某种意义上讲 key 的数量决定了最终嵌套结果的深度。

    nest.sortKeys(comparator) <源码>

    为 current key(当前 key) 指定一个 comparator 函数用以对当前 key 下的元素排序。和 d3.ascendingd3.descending 类似。如果没有指定,则默认的 key 排序为 undefined。例如,在第一层和第二次分别根据 yearvarieties 进行排序:

    var entries = d3.nest()
        .key(function(d) { return d.year; }).sortKeys(d3.ascending)
        .key(function(d) { return d.variety; }).sortKeys(d3.descending)
        .entries(yields);
    

    排序操作仅仅影响 nest.entries 的结果。因为 nest.map 和 nest.object 返回的 keys 的顺序总是是未知的。

    nest.sortValues(comparator) <源码>

    为嵌套操作的叶节点指定一个 comparator,和 d3.ascendingd3.descending 类似。这与对数组进行嵌套重组之前进行排序是大致一致的。如果没有指定比较函数,则元素的顺序会依照输入数组的顺序排序。这个操作对 nest.map, nest.entries 和 nest.object 都有影响。

    nest.rollup(function) <源码>

    指定一个 rollup(归纳) 函数,应用在每个分组的叶节点上。归纳函数的返回值将代替由 nest.map 或 nest.object 返回的叶节点元素。对于nest.entries 操作,它会代替用 entry.value 代替 entry.values。如果指定了 leaf comparator 则叶节会在调用归纳函数之前调用。函数参数会传递当前叶节点组。注意:上述操作都在定义嵌套的行为,要将嵌套应用到具体的数据上,需要调用 nest.map, nest.object 或者 nest.entries 方法来获取嵌套后的具体形式

    nest.map(array) <源码>

    将嵌套操作应用到指定的数组,并返回嵌套后的 [map]("https://github.com/d3/d3-collection/blob/master/src/nest.js" title="Source" target="_blank" rel="noopener noreferrer"><源码>

    将指定的嵌套操作应用到指定的 array, 返回一个嵌套对象。返回的关联数组中的每一项都与第一个 key 函数相关。每一项的值取决于 key 函数的个数:如果不止一个 key 函数则值为一个关联数组,否则是经过 key 函数过滤之后的数组。

    注意的是如果输入数组中包括与 JavaScript 内置 key(比如__proto__)冲突的话是不安全的。如果不能保证数组中所有的 key 都是安全的请使用 nest.map 代替。

    nest.entries(array) <源码>

    将指定的嵌套操作应用到指定的 array,返回经过嵌套处理后的 key-values 对。与将 map.entries 应用到关联数组类似。但是具有层次结构,嵌套体现在 value,如果指定了多个 key 则如果对应的 key 下有数据的话,其 value 也为一个 key-values 对象,以此类推。