9

我有这个 JSON 数据结构:

[
    { "dep": "d1", "name": "name1", "size": "size1" },
    { "dep": "d1", "name": "name2", "size": "size2" },
    { "dep": "d2", "name": "name1", "size": "size3" },
    { "dep": "d2", "name": "name1", "size": "size4" }
]

我想把它转换成这样的嵌套结构:

{
    "name": "root",
    "children": [
        { "name": "d1",
            "children": [
                { "dep": "d1", "name": "name1", "size": "size1" },
                { "dep": "d1", "name": "name2", "size": "size2" }
            ]
        },
        { "name": "d2",
            "children": [
                { "dep": "d2", "name": "name1", "size": "size3" },
                { "dep": "d2", "name": "name2", "size": "size4" }
            ]
        }
    ]
}

...并进一步使用它来制作Reingold-Tilford 树。谁能指出我正确的方向,我对 D3 很陌生!

4

5 回答 5

9

策略是根据你想要的创建一个新的空数据结构,然后通过遍历整个原始数据集来填充它。这是代码:

var data = [
    { "dep": "d1", "name": "name1", "size": "size1" },
    { "dep": "d1", "name": "name2", "size": "size2" },
    { "dep": "d2", "name": "name1", "size": "size3" },
    { "dep": "d2", "name": "name2", "size": "size4" }
]

var newData = {"name": "root", "children": {}}

data.forEach(function (d) {
    if (typeof newData.children[d.dep] !== 'undefined') {
        newData.children[d.dep].children.push(d)
    } else {
        newData.children[d.dep] = {"name": d.dep, "children": [d]}
    }
})
newData.children = Object.keys(newData.children).map(function (key) {
    return newData.children[key];
});

最后的赋值是将对象转换为数组。

这给出了所需的结果newData

{
    "name": "root",
    "children": [
        { "name": "d1",
            "children": [
                { "dep": "d1", "name": "name1", "size": "size1" },
                { "dep": "d1", "name": "name2", "size": "size2" }
            ]
        },
        { "name": "d2",
            "children": [
                { "dep": "d2", "name": "name1", "size": "size3" },
                { "dep": "d2", "name": "name2", "size": "size4" }
            ]
        }
    ]
}

jsFiddle:http: //jsfiddle.net/chrisJamesC/eB4jF/

注意:此方法不适用于嵌套结构。对嵌套结构执行此操作会更加困难,但您始终可以使用递归函数。


编辑:正如@imarane 在他的回答中所建议的,您可以使用d3.nest()这比我手工制作的解决方案要好得多。你可能会因此接受他的回答。通过玩它,甚至可以很容易地拥有多层嵌套:

var data = [
    { "dep": "d1", "name": "name1", "size": "size1" },
    { "dep": "d1", "name": "name2", "size": "size2" },
    { "dep": "d2", "name": "name1"},
    { "dep": "d2"}
]

var newData = {
    "key":"root", 
    "children": 
        d3.nest()
            .key(function(d){return d.dep})
            .key(function(d){return d.name})
            .key(function(d){return d.size})
            .entries(data)
}     

其中给出:

{"key":"root","children":[
    {"key":"d1","values":[
        {"key":"name2","values":[
            {"dep":"d1","name":"name2","size":"size1"},
            {"dep":"d1","name":"name2","size":"size2"}
        ]}
    ]},
    {"key":"d2","values":[
        {"key":"name1","values":[
            {"dep":"d2","name":"name1"}
        ]},
        {"key":"undefined","values":[
            {"dep":"d2"}
        ]}
    ]}
]}

其中以下数据结构(我希望能更好地理解整点):

var data = [
    { "dep": "d1", "name": "name2", "size": "size1" },
    { "dep": "d1", "name": "name2", "size": "size2" },
    { "dep": "d2", "name": "name1"},
    { "dep": "d2"}
]

JsFiddle:http: //jsfiddle.net/chrisJamesC/eB4jF/2/

更多关于 Nest: http ://bl.ocks.org/phoebebright/raw/3176159/

于 2013-04-10T00:08:15.583 回答
4

另一种选择是使用 D3 内置的嵌套方法....

var nested = d3.nest()
.key(function(d,i){ return d.dep; })
.entries(data);

输出:

 [
  {
    "key": "d1",
    "values": [
      {
        "dep": "d1",
        "name": "name1",
        "size": "size1"
      },
      {
        "dep": "d1",
        "name": "name2",
        "size": "size2"
      }
    ]
  },
  {
    "key": "d2",
    "values": [
      {
        "dep": "d2",
        "name": "name1",
        "size": "size3"
      },
      {
        "dep": "d2",
        "name": "name2",
        "size": "size4"
      }
    ]
  }
]

JsFiddle:http: //jsfiddle.net/imrane/bSGrG/1/

于 2013-04-10T03:46:15.043 回答
1

由于d3-collection已被弃用d3.array,我们可以使用d3.groups来实现以前使用的功能d3.nest

var output = {
  "name": "root",
  "children": d3.groups(input, d => d.dep).map(([k, vs]) => ({ "name": k, "children": vs }))
};

例如:

var input = [
  { "dep": "d1", "name": "name1", "size": "size1" },
  { "dep": "d1", "name": "name2", "size": "size2" },
  { "dep": "d2", "name": "name1", "size": "size3" },
  { "dep": "d2", "name": "name1", "size": "size4" }
];

var output = {
  "name": "root",
  "children": d3.groups(input, d => d.dep).map(([k, vs]) => ({ "name": k, "children": vs }))
};

console.log(output);
<script src="https://d3js.org/d3-array.v2.min.js"></script>

于 2019-06-16T16:03:12.020 回答
0

嘿伙计们,我想我找到了一个相当简单的解决方案。我以非常流线型的方式为分层条形图完成了一个非常好的大型数据集(400,000 行)嵌套。它利用了 Underscore 库和一个附加功能_.nest。只需下载并包含必要的两个库

src="underscore-min.js"
src="underscore.nest.js"

然后使用该_.nest函数创建您的结构。这是我的台词:

var newdata = _.nest(data, ["Material", "StudyName"]);

"Material"并且"StudyName"是我想要将我的结构分组到的列。

如果您需要完成更多事情,还有其他选项可以使用此功能,但我会这样保留

于 2014-10-22T14:39:17.173 回答
0

用这个。如果需要,您可以在浏览器的控制台中检查输出。

function reSortRoot(root, value_key) {
                //console.log("Calling");
                for ( var key in root) {
                    if (key == "key") {
                        root.name = root.key;
                        delete root.key;
                    }
                    if (key == "values") {
                        root.children = [];
                        for (item in root.values) {
                            root.children.push(reSortRoot(root.values[item],
                                    value_key));
                        }
                        delete root.values;
                    }
                    if (key == value_key) {
                        root.value = parseFloat("1");
                        delete root[value_key];
                    }
                }
                return root;
            } 

            var testdata=[
                          { "dep": "d1", "name": "name1", "size": "size1" },
                          { "dep": "d1", "name": "name2", "size": "size2" },
                          { "dep": "d2", "name": "name1", "size": "size3" },
                          { "dep": "d2", "name": "name1", "size": "size4" }
                      ];

            var testJson = d3.nest()
            .key(function(d)  { return d.dep; })
            .entries(testdata); 
             console.log(testJson);

            var testRoot={};
            testRoot.key = "Information";
            testRoot.values = testJson;
            testRoot = reSortRoot(testRoot, "name");

             console.log(testRoot);
于 2015-07-29T18:31:27.777 回答