Javascript:构建层次结构树
我的数据具有以下属性:Javascript:构建层次结构树,javascript,Javascript,我的数据具有以下属性: 每个条目都有一个唯一的id(id) 每个都有一个父字段,该字段指向父字段的Id 一个节点可以有多个子节点,但只能有一个父节点 下面是我第一次尝试建一棵树。这是错误的,因为递归会导致无限循环。即使我解决了这个问题,我也不确定是否有更好的方法来解决这个问题。目前,我做了两次 我希望它是尽可能有效的,因为我有一个体面的数据量。它还需要动态重建树(根可以是任何节点) 以下程序中有示例数据: arry = [{"Id":"1", "Name":"abc", "Parent":""
arry = [{"Id":"1", "Name":"abc", "Parent":""}, {"Id":"2", "Name":"abc", "Parent":"1"},
{"Id":"3", "Name":"abc", "Parent":"2"},{"Id":"4", "Name":"abc", "Parent":"2"}]//for testing
我希望输出是(可能是错误的嵌套结构,正如我手动编写的那样。但是,我希望是一个有效的JSON结构,节点作为字段“值”,子节点作为数组。)
示例程序:
function convertToHierarchy(arry, root)
{
//root can be treated a special case, as the id is known
arry = [{"Id":"1", "Name":"abc", "Parent":""}, {"Id":"2", "Name":"abc", "Parent":"1"},
{"Id":"3", "Name":"abc", "Parent":"2"},{"Id":"4", "Name":"abc", "Parent":"2"}]//for testing
var mapping = {}; // parent : [children]
for (var i = 0; i < array.length; i++)
{
var node = arry[i];
if (!mapping[node.Id]) {
mapping[node.Id] = {value: node, children:[] } ;
}else{
mapping[node.Id] = {value: node} //children is already set
}
if (!mapping[node.Parent]) { //TODO what if parent doesn't exist.
mapping[node.Parent] = {value: undefined, children:[ {value: node,children:[]} ]};
}else {//parent is already in the list
mapping[node.Parent].children.push({value: node,children:[]} )
}
}
//by now we will have an index with all nodes and their children.
//Now, recursively add children for root element.
var root = mapping[1] //hardcoded for testing, but a function argument
recurse(root, root, mapping)
console.log(root)
//json dump
}
function recurse(root, node, mapping)
{
var nodeChildren = mapping[node.value.Id].children;
root.children.push({value:node.value, children:nodeChildren})
for (var i = 0; i < nodeChildren.length; i++) {
recurse(root, nodeChildren[i], mapping);
}
return root;
}
这里有一个解决方案:
var items = [
{"Id": "1", "Name": "abc", "Parent": "2"},
{"Id": "2", "Name": "abc", "Parent": ""},
{"Id": "3", "Name": "abc", "Parent": "5"},
{"Id": "4", "Name": "abc", "Parent": "2"},
{"Id": "5", "Name": "abc", "Parent": ""},
{"Id": "6", "Name": "abc", "Parent": "2"},
{"Id": "7", "Name": "abc", "Parent": "6"},
{"Id": "8", "Name": "abc", "Parent": "6"}
];
function buildHierarchy(arry) {
var roots = [], children = {};
// find the top level nodes and hash the children based on parent
for (var i = 0, len = arry.length; i < len; ++i) {
var item = arry[i],
p = item.Parent,
target = !p ? roots : (children[p] || (children[p] = []));
target.push({ value: item });
}
// function to recursively build the tree
var findChildren = function(parent) {
if (children[parent.value.Id]) {
parent.children = children[parent.value.Id];
for (var i = 0, len = parent.children.length; i < len; ++i) {
findChildren(parent.children[i]);
}
}
};
// enumerate through to handle the case where there are multiple roots
for (var i = 0, len = roots.length; i < len; ++i) {
findChildren(roots[i]);
}
return roots;
}
console.log(buildHierarchy(items));
var项目=[
{“Id”:“1”,“Name”:“abc”,“Parent”:“2”},
{“Id”:“2”,“Name”:“abc”,“Parent”:“},
{“Id”:“3”,“Name”:“abc”,“Parent”:“5”},
{“Id”:“4”,“Name”:“abc”,“Parent”:“2”},
{“Id”:“5”,“Name”:“abc”,“Parent”:“},
{“Id”:“6”,“Name”:“abc”,“Parent”:“2”},
{“Id”:“7”,“Name”:“abc”,“Parent”:“6”},
{“Id”:“8”,“Name”:“abc”,“Parent”:“6”}
];
函数构建层次结构(arry){
变量根=[],子类={};
//查找顶级节点并基于父节点散列子节点
对于(变量i=0,len=arry.length;i
这是另一个。这适用于多个根节点:
function convertToHierarchy() {
var arry = [{ "Id": "1", "Name": "abc", "Parent": "" },
{ "Id": "2", "Name": "abc", "Parent": "1" },
{ "Id": "3", "Name": "abc", "Parent": "2" },
{ "Id": "4", "Name": "abc", "Parent": "2"}];
var nodeObjects = createStructure(arry);
for (var i = nodeObjects.length - 1; i >= 0; i--) {
var currentNode = nodeObjects[i];
//Skip over root node.
if (currentNode.value.Parent == "") {
continue;
}
var parent = getParent(currentNode, nodeObjects);
if (parent == null) {
continue;
}
parent.children.push(currentNode);
nodeObjects.splice(i, 1);
}
//What remains in nodeObjects will be the root nodes.
return nodeObjects;
}
function createStructure(nodes) {
var objects = [];
for (var i = 0; i < nodes.length; i++) {
objects.push({ value: nodes[i], children: [] });
}
return objects;
}
function getParent(child, nodes) {
var parent = null;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].value.Id == child.value.Parent) {
return nodes[i];
}
}
return parent;
}
函数convertToHierarchy(){
var arry=[{“Id”:“1”,“Name”:“abc”,“Parent”:“},
{“Id”:“2”,“Name”:“abc”,“Parent”:“1”},
{“Id”:“3”,“Name”:“abc”,“Parent”:“2”},
{“Id”:“4”,“Name”:“abc”,“Parent”:“2”}];
var nodeObjects=createStructure(arry);
对于(var i=nodeObjects.length-1;i>=0;i--){
var currentNode=节点对象[i];
//跳过根节点。
如果(currentNode.value.Parent==“”){
继续;
}
var parent=getParent(当前节点、节点对象);
如果(父项==null){
继续;
}
parent.children.push(当前节点);
节点对象拼接(i,1);
}
//节点对象中剩下的将是根节点。
返回节点对象;
}
函数createStructure(节点){
var对象=[];
对于(var i=0;i
我会这样做的。它处理多个根节点,在IMO中可读性相当好
array = [{"Id":"1", "Name":"abc", "Parent":""},
{"Id":"2", "Name":"abc", "Parent":"1"},
{"Id":"3", "Name":"abc", "Parent":"2"},
{"Id":"4", "Name":"abc", "Parent":"2"},
{"Id":"5", "Name":"abc", "Parent":""},
{"Id":"6", "Name":"abc", "Parent":"5"}];
function buildHierarchy(source)
{
Array.prototype.insertChildAtId = function (strId, objChild)
{
// Beware, here there be recursion
found = false;
for (var i = 0; i < this.length ; i++)
{
if (this[i].value.Id == strId)
{
// Insert children
this[i].children.push(objChild);
return true;
}
else if (this[i].children)
{
// Has children, recurse!
found = this[i].children.insertChildAtId(strId, objChild);
if (found) return true;
}
}
return false;
};
// Build the array according to requirements (object in value key, always has children array)
var target = [];
for (var i = 0 ; i < array.length ; i++)
target.push ({ "value": source[i], "children": []});
i = 0;
while (target.length>i)
{
if (target[i].value.Parent)
{
// Call recursion to search for parent id
target.insertChildAtId(target[i].value.Parent, target[i]);
// Remove node from array (it's already been inserted at the proper place)
target.splice(i, 1);
}
else
{
// Just skip over root nodes, they're no fun
i++;
}
}
return target;
}
console.log(buildHierarchy(array));
array=[{“Id”:“1”,“Name”:“abc”,“Parent”:“},
{“Id”:“2”,“Name”:“abc”,“Parent”:“1”},
{“Id”:“3”,“Name”:“abc”,“Parent”:“2”},
{“Id”:“4”,“Name”:“abc”,“Parent”:“2”},
{“Id”:“5”,“Name”:“abc”,“Parent”:“},
{“Id”:“6”,“Name”:“abc”,“Parent”:“5”}];
函数构建层次结构(源)
{
Array.prototype.insertchildataid=函数(strId,objChild)
{
//注意,这里有递归
发现=错误;
for(var i=0;ii)
{
if(目标[i].value.Parent)
{
//调用递归来搜索父id
target.insertchildataid(target[i].value.Parent,target[i]);
//从阵列中删除节点(已将其插入到正确的位置)
靶剪接(i,1);
}
其他的
{
//只需跳过根节点,它们就没意思了
i++;
}
}
回报目标;
}
log(buildHierarchy(array));
在ES6中实现,使用简单的示例输入。可以在浏览器控制台中进行测试
let array = [{ id: 'a', children: ['b', 'c'] }, { id: 'b', children: [] }, { id: 'c', children: ['b', 'd'] }, { id: 'd', children: ['b'] }],
tree = (data) => {
let nodes = Object.create(null),
result = {};
data.forEach((item) => {
if (!nodes[item.id]) {
nodes[item.id] = {id: item.id, children: []}
result = nodes
}
item.children.forEach((child) => {
nodes[child] = {id: child, children: []}
nodes[item.id].children.push(nodes[child])
})
})
return result
}
console.log(tree(array))
虽然上述解决方案确实有效-但我认为它们非常缓慢,没有太多的循环和过时的方法(我们将使用ES6语法)。我建议使用下面的优化解决方案,这将提高您的性能
javascript
const层次结构=(数据)=>{
常量树=[];
常量childOf={};
data.forEach((项目)=>{
const{Id,Parent}=项;
childOf[Id]=childOf[Id]| |[];
item.children=childOf[Id];
帕
array = [{"Id":"1", "Name":"abc", "Parent":""},
{"Id":"2", "Name":"abc", "Parent":"1"},
{"Id":"3", "Name":"abc", "Parent":"2"},
{"Id":"4", "Name":"abc", "Parent":"2"},
{"Id":"5", "Name":"abc", "Parent":""},
{"Id":"6", "Name":"abc", "Parent":"5"}];
function buildHierarchy(source)
{
Array.prototype.insertChildAtId = function (strId, objChild)
{
// Beware, here there be recursion
found = false;
for (var i = 0; i < this.length ; i++)
{
if (this[i].value.Id == strId)
{
// Insert children
this[i].children.push(objChild);
return true;
}
else if (this[i].children)
{
// Has children, recurse!
found = this[i].children.insertChildAtId(strId, objChild);
if (found) return true;
}
}
return false;
};
// Build the array according to requirements (object in value key, always has children array)
var target = [];
for (var i = 0 ; i < array.length ; i++)
target.push ({ "value": source[i], "children": []});
i = 0;
while (target.length>i)
{
if (target[i].value.Parent)
{
// Call recursion to search for parent id
target.insertChildAtId(target[i].value.Parent, target[i]);
// Remove node from array (it's already been inserted at the proper place)
target.splice(i, 1);
}
else
{
// Just skip over root nodes, they're no fun
i++;
}
}
return target;
}
console.log(buildHierarchy(array));
let array = [{ id: 'a', children: ['b', 'c'] }, { id: 'b', children: [] }, { id: 'c', children: ['b', 'd'] }, { id: 'd', children: ['b'] }],
tree = (data) => {
let nodes = Object.create(null),
result = {};
data.forEach((item) => {
if (!nodes[item.id]) {
nodes[item.id] = {id: item.id, children: []}
result = nodes
}
item.children.forEach((child) => {
nodes[child] = {id: child, children: []}
nodes[item.id].children.push(nodes[child])
})
})
return result
}
console.log(tree(array))