在javascript中将数组转换为嵌套对象
我有典型的组织结构在javascript中将数组转换为嵌套对象,javascript,arrays,node.js,tree,Javascript,Arrays,Node.js,Tree,我有典型的组织结构层次结构。比如说 D,E is reporting to B. B,C is reporting to A. A是最上面的节点。但我接收到的数据是一个平面数组,其属性指向父对象 [{ name: "A", parent: null }, { name: "B", parent: "A" }, { name: "C", parent: "A" }, {
层次结构。比如说
D,E is reporting to B. B,C is reporting to A.
A是最上面的节点。但我接收到的数据是一个平面数组,其属性指向父对象
[{
name: "A",
parent: null
},
{
name: "B",
parent: "A"
},
{
name: "C",
parent: "A"
},
{
name: "D",
parent: "B"
},
{
name: "E",
parent: "B"
}]
但我想将其转换为单个嵌套对象
或树
。根节点具有嵌入子节点的children属性,每个子节点都有自己的children属性,如下所示
{
name: "A",
children: [{
name: "C"
children: [{
name: "D"
},{
name: "E"
}]
},{
name: "C"
}]
}
如何在javascript中高效地执行此操作 您可以使用while循环执行此操作:
var data = [
{ name: "A", parent: null },
{ name: "B", parent: "A" },
{ name: "C", parent: "A" },
{ name: "D", parent: "B" },
{ name: "E", parent: "B" }
];
var root = data.find(function(item) {
return item.parent === null;
});
var tree = {
name: root.name
};
var parents = [tree];
while (parents.length > 0) {
var newParents = [];
parents.forEach(function(parent) {
var childs = data.filter(function(item) {
return item.parent == parent.name
}).forEach(function(child) {
var c = { name: child.name };
parent.children = parent.children || [];
parent.children.push(c);
newParents.push(c);
});
});
parents = newParents;
}
console.log(tree);
与其他解决方案不同,它使用单个循环-数据的顺序不重要-示例与问题的顺序不同
var peeps = [
{ name: "D", parent: "B" },
{ name: "B", parent: "A" },
{ name: "A", parent: null },
{ name: "C", parent: "A" },
{ name: "E", parent: "B" }
];
var tree;
var obj = {};
peeps.forEach(function (peep) {
var name = peep.name,
parent = peep.parent,
a = obj[name] || { name: name };
if (parent) {
obj[parent] = obj[parent] || { name: parent };
obj[parent].children = obj[parent].children || [];
obj[parent].children.push(a);
} else {
tree = obj[name];
}
obj[name] = obj[name] || a;
});
console.log(tree);
此解决方案以Jaromanda X'为特色,并添加了一些功能
Array.prototype.reduce
而不是Array.prototype.forEach
,因为需要临时变量和返回值
r[a.name].children的内容将被保留并分配给a.children
节点a
被分配给r[a.name]
。因此,节点对象的所有属性保持不变,如prop1
<代码>prop5
根节点被分配到r.
以供以后使用
var数据=[
{名称:“D”,父项:“B”,prop1:'prop1'},
{名称:“B”,父级:“A”,prop2:'prop2'},
{name:“A”,父项:null,prop3:'prop3'},
{名称:“C”,父级:“A”,prop4:'prop4'},
{名称:“E”,父项:“B”,prop5:'prop5'}
],
tree=data.reduce(函数(r,a){
a、 children=r[a.name]&&r[a.name]。children;
r[a.name]=a;
如果(a.父母){
r[a.parent]=r[a.parent]| |{};
r[a.parent]。children=r[a.parent]。children | |[];
r[a.parent].children.push(a);
}否则{
r、 _uA=a;
}
返回r;
}, {})._;
document.write(“”+JSON.stringify(tree,0,4)+“”)代码>如果提供的数组顺序不正确,则此操作将失败。var data=[,{name:“B”,parent:“A”},{name:“A”,parent:null},{name:“C”,parent:“A”},{name:“D”,parent:“B”},{name:“E”,parent:“B”}];例如,它会崩溃。@SimonBrahan不,它不会失败。您忘记删除数据中的逗号了。@madox2,它应该是console.log(tree)
,对吗?你能解释一下这是怎么回事吗?您没有在任何地方修改树对象,但结果是在树中。我很困惑。@espeirasbora你是对的,那是一种打字错误。我批准编辑以修复a=obj[name]| |{name:name}
在这里,您可以使用peep代替新对象,并将a
替换为obj[name]
,完成obj[name]=obj[name]|peep
其中a
只使用obj[name]
现在您可以删除最后一行obj[name]=obj[name]|a代码>@NinaScholz对此不确定。你试过了吗?首先,输出格式不包括parent
属性。此外,在代码的疯狂背后还有一种方法,允许输入数据以任意顺序排列。请看我的答案。关于属性父属性
,您是对的,我只包括所有属性。(op没有问他们)。我有类似的代码,使用reduce,并且reduce变量上有一个“特殊”属性,甚至称之为\uuu
-我认为这可能会让op有点不知所措-但是我仍然使用我的逻辑返回请求的确切结构:pSorry for necropposting,但是..如果有一些根注释,而不是只有一个,其中parent为Null,那么您的两个代码都不起作用。@DenimTornado,请参阅第2部分了解多个根元素。@NinaScholz很酷,它可以工作,请稍等,您能澄清一下“.Null.children;”part在末尾吗?r[a.parent]
创建了一个带有'Null'
(null
as string,因为所有键都是字符串)as key,这是根对象的已知符号。这用于获取它的子对象。