如何将这些数据编码为JSON中的父/子结构
how to encode this data to parent / children structure in JSON
我正在使用d3.js将动物(生物体)家族(一次多达4000个)可视化为树状图,尽管数据源也可以是目录列表或命名对象列表。我的数据看起来像:
json = {
organisms:[
{name: 'Hemiptera.Miridae.Kanakamiris'},
{name: 'Hemiptera.Miridae.Neophloeobia.incisa'},
{name: 'Lepidoptera.Nymphalidae.Ephinephile.rawnsleyi'},
... etc ...
]
}
我的问题是:我正试图找到将上述数据转换为分层父/子数据结构的最佳方法,正如许多d3可视化(如树图)所使用的那样(有关数据示例,请参阅d3/examples/data/目录中的flare.json)。以下是所需数据结构的示例:
{"name": "ROOT",
"children": [
{"name": "Hemiptera",
"children": [
{"name": "Miridae",
"children": [
{"name": "Kanakamiris", "children":[]},
{"name": "Neophloeobia",
"children": [
{"name": "incisa", "children":[] }
]}
]}
]},
{"name": "Lepidoptera",
"children": [
{"name": "Nymphalidae",
"children": [
{"name": "Ephinephile",
"children": [
{"name": "rawnsleyi", "children":[] }
]}
]}
]}
]}
}
EDIT:将所有原始所需的数据结构封装在ROOT
节点内,以符合d3示例的结构,d3示例只有一个主父节点。
我希望了解一个通用的设计模式,作为奖励,我希望看到一些javascript、php(甚至python)的解决方案。javascript是我的首选。关于php:我实际使用的数据来自php脚本对数据库的调用,该脚本将结果编码为json。php脚本中的数据库结果是一个有序数组(见下文),如果这对基于php的答案有用的话。
Array
(
[0] => Array
(
['Rank_Order'] => 'Hemiptera'
['Rank_Family'] => 'Miridae'
['Rank_Genus'] => 'Kanakamiris'
['Rank_Species'] => ''
) ........
其中:'Rank_Order'
是'Rank_Family'
是'Rank_Genus'
是'Rank_Species'
的父母
我在这里问了一个类似的问题,重点是php解决方案,但唯一的答案是在我的服务器上不工作,而且我不太明白发生了什么,所以我想从设计模式的角度来问这个问题,并引用我在javascript和d3.js中的实际使用。
以下是您所提供的结构的具体内容,可以很容易地使其更通用。我相信addChild函数可以简化。希望这些评论能有所帮助。
function toHeirarchy(obj) {
// Get the organisms array
var orgName, orgNames = obj.organisms;
// Make root object
var root = {name:'ROOT', children:[]};
// For each organism, get the name parts
for (var i=0, iLen=orgNames.length; i<iLen; i++) {
orgName = orgNames[i].name.split('.');
// Start from root.children
children = root.children;
// For each part of name, get child if already have it
// or add new object and child if not
for (var j=0, jLen=orgName.length; j<jLen; j++) {
children = addChild(children, orgName[j]);
}
}
return root;
// Helper function, iterates over children looking for
// name. If found, returns its child array, otherwise adds a new
// child object and child array and returns it.
function addChild(children, name) {
// Look for name in children
for (var i=0, iLen=children.length; i<iLen; i++) {
// If find name, return its child array
if (children[i].name == name) {
return children[i].children;
}
}
// If didn't find name, add a new object and
// return its child array
children.push({'name': name, 'children':[]});
return children[children.length - 1].children;
}
}
给定您的起始输入,我相信下面的代码会产生您想要的输出。我不认为这是最漂亮的方法,但这是当时我想到的。
对数据进行预处理似乎最容易,首先将初始字符串数组拆分为如下数组:
[
["Hemiptera","Miridae","Kanakamiris" ],
["Hemiptera","Miridae","Neophloeobia","incisa" ],
//etc
]
然后处理它,得到一个类似于的工作对象
working = {
Hemiptera : {
Miridae : {
Kanakamiris : {},
Neophloeobia : {
incisa : {}
}
}
},
Lepidoptera : {
Nymphalidae : {
Ephinephile : {
rawnsleyi : {}
}
}
}
}
因为使用对象而不是数组可以更容易地测试子项是否已经存在。创建了上述结构后,我最后一次对其进行处理,以获得您想要的最终输出。因此:
// start by remapping the data to an array of arrays
var organisms = data.organisms.map(function(v) {
return v.name.split(".");
});
// this function recursively processes the above array of arrays
// to create an object whose properties are also objects
function addToHeirarchy(val, level, heirarchy) {
if (val[level]) {
if (!heirarchy.hasOwnProperty(val[level]))
heirarchy[val[level]] = {};
addToHeirarchy(val, level + 1, heirarchy[val[level]]);
}
}
var working = {};
for (var i = 0; i < organisms.length; i++)
addToHeirarchy(organisms[i], 0, working);
// this function recursively processes the object created above
// to create the desired final structure
function remapHeirarchy(item) {
var children = [];
for (var k in item) {
children.push({
"name" : k,
"children" : remapHeirarchy(item[k])
});
}
return children;
}
var heirarchy = {
"name" : "ROOT",
"children" : remapHeirarchy(working)
};
演示:http://jsfiddle.net/a669F/1/
我自己问题的另一个答案。。。。在过去的一天里,我没有学到太多关于d3.js的知识,关于这个问题,d3.nest()与.key()和.entries()是我的朋友(所有d3函数)。这个答案涉及到更改初始数据,因此它可能不适合作为我问的特定问题的好答案。然而,如果有人有类似的问题,可以在服务器上更改内容,那么这是一个非常简单的解决方案:
以以下格式返回数据库中的数据:
json = {'Organisms': [
{ 'Rank_Order': 'Hemiptera',
'Rank_Family': 'Miridae',
'Rank_Genus': 'Kanakamiris',
'Rank_Species': '' },
{}, ...
]}
然后使用d3.nest()
organismNest = d3.nest()
.key(function(d){return d.Rank_Order;})
.key(function(d){return d.Rank_Family;})
.key(function(d){return d.Rank_Genus;})
.key(function(d){return d.Rank_Species;})
.entries(json.Organism);
返回:
{
key: "Hemiptera"
values: [
{
key: "Cicadidae"
values: [
{
key: "Pauropsalta "
values: [
{
key: "siccanus"
values: [
Rank_Family: "Cicadidae"
Rank_Genus: "Pauropsalta "
Rank_Order: "Hemiptera"
Rank_Species: "siccanus"
AnotherOriginalDataKey: "original data value"
etc etc, nested and lovely
这返回的内容与我在上面的问题中描述为我想要的格式的they数组非常相似,但有一些不同。特别是,没有全封闭的ROOT元素,而且我最初想要的键是"name"answers"children"。nest()将键分别返回为"key"answers"values"。通过定义适当的数据访问器函数(d3的基本概念),这些替换键在d3.js中很容易使用。。。但这已经超出了问题的最初范围。。。希望这对某人也有帮助
- 更改JSON对象的结构
- 如何将我的json结构转换为C3.js所需的列结构
- 从json对象聚集数据并创建层次结构
- 如何迭代json对象结构以只获取名称
- 如何解析文本区域中的结构化字符串数据(接近JSON)以检索其所需的属性
- 生成目录结构的JSON供Webix树小部件使用
- 复杂的 JSON 结构 + 道场选择
- 如何从 json 嵌套结构中获取键的 json 值
- JSON 层次结构,如何获取元素
- 如何更改我的 json 结构
- JavaScript - JSON 数据结构的构建 - 如何使用变量值更改键名
- 如何获取json结构中键的单个特定值
- 将json结构转换为可用的javascript数据集
- 从JSON结构定义中获取JSON值
- 从文件目录结构创建JSON数据的有效功能
- 用Javascript从两个平面结构数组中格式化JSON
- 与restify一起,我的帖子显示了一个“;将循环结构转换为JSON”;错误
- 如何以类似 JSON 的格式打印圆形结构
- 比较两个循环结构JSON对象
- 未捕获的类型错误:转换圆形结构JSON(仅在Chrome上)