在 javascript 中将数组转换为嵌套对象
Converting an array into a nested object in javascript
我有典型的组织hierarchy
。例如。
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"
}]
但我想将其转换为 single nested object
或 tree
。根节点具有嵌入子节点的子节点属性,每个子节点都有自己的子节点属性,如下所示。
{
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
,因为需要临时变量和 return 值。
保留r[a.name].children
的内容赋值给a.children
.
节点 a
已分配给 r[a.name]
。因此,节点对象的所有属性都会保留,例如 prop1
... prop5
.
根节点分配给r._
以备后用
var data = [
{ name: "D", parent: "B", prop1: 'prop1' },
{ name: "B", parent: "A", prop2: 'prop2' },
{ name: "A", parent: null, prop3: 'prop3' },
{ name: "C", parent: "A", prop4: 'prop4' },
{ name: "E", parent: "B", prop5: 'prop5' }
],
tree = data.reduce(function (r, a) {
a.children = r[a.name] && r[a.name].children;
r[a.name] = a;
if (a.parent) {
r[a.parent] = r[a.parent] || {};
r[a.parent].children = r[a.parent].children || [];
r[a.parent].children.push(a);
} else {
r._ = a;
}
return r;
}, {})._;
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');
对于多个根,您可以使用根的父节点作为子节点的访问器,return这个数组
var data = [{ name: "D", parent: "B", prop1: 'prop1' }, { name: "B", parent: "A", prop2: 'prop2' }, { name: "A", parent: null, prop3: 'prop3' }, { name: "C", parent: "A", prop4: 'prop4' }, { name: "E", parent: "B", prop5: 'prop5' }, { name: "A1", parent: null, prop3: 'prop3' }],
tree = data.reduce(function (r, a) {
if (r[a.name] && r[a.name].children) { // prevent empty children array
a.children = r[a.name].children;
}
r[a.name] = a;
r[a.parent] = r[a.parent] || {};
r[a.parent].children = r[a.parent].children || [];
r[a.parent].children.push(a);
return r;
}, {}).null.children; // take root value as property accessor
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
我有典型的组织hierarchy
。例如。
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"
}]
但我想将其转换为 single nested object
或 tree
。根节点具有嵌入子节点的子节点属性,每个子节点都有自己的子节点属性,如下所示。
{
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
,因为需要临时变量和 return 值。保留
r[a.name].children
的内容赋值给a.children
.节点
a
已分配给r[a.name]
。因此,节点对象的所有属性都会保留,例如prop1
...prop5
.根节点分配给
r._
以备后用
var data = [
{ name: "D", parent: "B", prop1: 'prop1' },
{ name: "B", parent: "A", prop2: 'prop2' },
{ name: "A", parent: null, prop3: 'prop3' },
{ name: "C", parent: "A", prop4: 'prop4' },
{ name: "E", parent: "B", prop5: 'prop5' }
],
tree = data.reduce(function (r, a) {
a.children = r[a.name] && r[a.name].children;
r[a.name] = a;
if (a.parent) {
r[a.parent] = r[a.parent] || {};
r[a.parent].children = r[a.parent].children || [];
r[a.parent].children.push(a);
} else {
r._ = a;
}
return r;
}, {})._;
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');
对于多个根,您可以使用根的父节点作为子节点的访问器,return这个数组
var data = [{ name: "D", parent: "B", prop1: 'prop1' }, { name: "B", parent: "A", prop2: 'prop2' }, { name: "A", parent: null, prop3: 'prop3' }, { name: "C", parent: "A", prop4: 'prop4' }, { name: "E", parent: "B", prop5: 'prop5' }, { name: "A1", parent: null, prop3: 'prop3' }],
tree = data.reduce(function (r, a) {
if (r[a.name] && r[a.name].children) { // prevent empty children array
a.children = r[a.name].children;
}
r[a.name] = a;
r[a.parent] = r[a.parent] || {};
r[a.parent].children = r[a.parent].children || [];
r[a.parent].children.push(a);
return r;
}, {}).null.children; // take root value as property accessor
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }