将平面结构转换为分层结构
Converting flat structure to hierarchical
我需要创建能够将平面对象转换为递归对象的函数。下面是我的例子:我有一个平面数组:
var flatArray = [
{
Description: "G",
guid: "c8e63b35",
parent: null,
},
{
Description: "Z",
guid: "b1113b35",
parent: "c8e63b35",
},
{
Description: "F",
guid: "d2cc2233",
parent: "b1113b35",
},
{
Description: "L",
guid: "a24a3b1a",
parent: null,
},
{
Description: "K",
guid: "cd3b11caa",
parent: "a24a3b1a",
},
]
结果应该是:
recursiveArray = [
{
Description: "G",
guid: "c8e63b35",
parent: null,
Children: [
{
Description: "Z",
guid: "b1113b35",
parent: "c8e63b35",
Children: [
{
Description: "F",
guid: "d2cc2233",
parent: "b1113b35",
}
]
},
]
},
{
Description: "L",
guid: "a24a3b1a",
parent: null,
Children: [
{
Description: "K",
guid: "cd3b11caa",
parent: "a24a3b1a",
}
}
]
请帮我找出做这件事的方法。一个工作算法将受到赞赏,因为我有问题,了解如何正确地做到这一点。在每种情况下,我都需要找到递归结构中检查元素的特定位置,并将其推入查找元素子数组。我认为这是愚蠢和低效的。有什么方法可以快速有效地做到这一点吗?
编辑:递归数组格式错误。现在应该没问题了。我的数组没有排序这个效果很好,很容易阅读:
function flatToHierarchy (flat) {
var roots = [] // things without parent
// make them accessible by guid on this map
var all = {}
flat.forEach(function(item) {
all[item.guid] = item
})
// connect childrens to its parent, and split roots apart
Object.keys(all).forEach(function (guid) {
var item = all[guid]
if (item.parent === null) {
roots.push(item)
} else if (item.parent in all) {
var p = all[item.parent]
if (!('Children' in p)) {
p.Children = []
}
p.Children.push(item)
}
})
// done!
return roots
}
我是这样做的:
var flatArray = [{
Description: "G",
guid: "c8e63b35",
parent: null,
}, {
Description: "Z",
guid: "b1113b35",
parent: "c8e63b35",
}, {
Description: "F",
guid: "d2cc2233",
parent: "b1113b35",
}, {
Description: "L",
guid: "a24a3b1a",
parent: null,
}, {
Description: "K",
guid: "cd3b11caa",
parent: "a24a3b1a",
}];
var recursiveArray = unflatten(flatArray);
alert(JSON.stringify(recursiveArray, null, 4));
<script>
function unflatten(items) {
return items.reduce(insert, {
res: [],
map: {}
}).res;
}
function insert(obj, item) {
var parent = item.parent;
var map = obj.map;
map[item.guid] = item;
if (parent === null) obj.res.push(item);
else {
var parentItem = map[parent];
if (parentItem.hasOwnProperty("Children"))
parentItem.Children.push(item);
else parentItem.Children = [item];
}
return obj;
}
</script>
当然,这只适用于你的flatArray
具有每个父级出现在其子级之前的属性。
希望对你有帮助。
我尝试用伪代码编写算法,最终得到的JS代码几乎可以工作(可能需要一些额外的验证/检查),但显示了解决问题的一般方法。
//Lets separate children (nodes with a parent) from roots (nodes without a parent)
var children = flatArray.filter(function(object){
return object.parent !== null;
});
var roots = flatArray.filter(function(object){
return object.parent === null;
});
//And add each child to the nodes tree
children.foreach(function(child){
recursiveAdd(roots, child);
});
//To add a children node, node tree is searched recursively for a parent
function recursiveAdd(nodes, child){
nodes.foreach(function(parent){
if(parent.guid === child.parent){
parent.Children = parent.Children | [];
parent.Children.add(child);
} else if(parent.Children) {
recursiveAdd(parent.Children, child);
}
});
}
//Temporary children array can be garbage collected
children = null;
//Resulting node tree
var recursiveArray = roots;
这个递归函数可能对你有好处:
var flatArray = [{
Description: "G",
guid: "c8e63b35",
parent: null,
Children: []
}, {
Description: "Z",
guid: "b1113b35",
parent: "c8e63b35",
Children: []
}, {
Description: "F",
guid: "d2cc2233",
parent: "b1113b35",
Children: []
}, {
Description: "L",
guid: "a24a3b1a",
parent: null,
Children: []
}, {
Description: "K",
guid: "cd3b11caa",
parent: "a24a3b1a",
Children: []
}, ];
for (var i = 0; i < flatArray.length; i++) {
recursive(flatArray[i]);
}
function recursive(a) {
for (var i = 0; i < flatArray.length; i++) {
if (flatArray[i].parent == a.guid) {
var b = flatArray[i];
recursive(b);
a.Children.push(b);
}
}
}
console.log(flatArray)
var flatArray = [
{
Description: "G",
guid: "c8e63b35",
parent: null,
},
{
Description: "Z",
guid: "b1113b35",
parent: "c8e63b35",
},
{
Description: "F",
guid: "d2cc2233",
parent: "b1113b35",
},
{
Description: "L",
guid: "a24a3b1a",
parent: null,
},
{
Description: "K",
guid: "cd3b11caa",
parent: "a24a3b1a",
},
];
//for printing
function htmlPrint(obj) {
document.write('<pre>'+JSON.stringify(obj,null,2)+'</pre>');
};
var guids = {};
var roots = [];
flatArray.forEach(function(node){
guids[node.guid] = node; //save into a hash
node.Children = []; //make sure it has a children array
//save it as root if it is a root
if(node.parent === null){ roots.push(node);}
});
flatArray.forEach(function(node){
//if it has a parent, add self to parent's children
var parent = guids[node.parent];
if(parent) parent.Children.push(node);
});
htmlPrint(roots);
你可以在Angular中使用下面的代码:
flatToHierarchy(flat: any[], parent: any = null, Key: string = 'id', parentKey: string = 'parentId') {
var leafs: any = [];
if (!parent) {
leafs = flat.filter((x: { [x: string]: any; }) => x[parentKey] === null);
} else {
leafs = flat.filter((x: { [x: string]: any; }) => x[parentKey] === parent[Key]);
}
if (!leafs || leafs.length == 0) {
return;
} else {
leafs.forEach((item: { children: any[]; }) => {
item.children = [];
item.children = this.flatToHierarchy(flat, item);
});
}
return leafs;
}
像这样使用
this.flatToHierarchy(flatItems);
相关文章:
- 更改JSON对象的结构
- 角度控制器结构
- 从键值结构中获取数据,并将其与AngularJS中ng重复的值进行比较
- 使用递归属性迭代保留属性结构
- 如何将我的json结构转换为C3.js所需的列结构
- 嵌套对象结构
- Redux应用程序结构-在哪里放置服务/业务逻辑
- 用于视频类型的MongoDB结构's
- javascript和php中的pancard结构验证
- 如何在砖石结构中订购DOM
- 如何解析结构不良的 html 代码
- 访问嵌套函数结构中的JavaScript父函数变量
- 为什么我们在ES2015中需要一个新的for循环结构,而我们已经有了for、forEach
- 从json对象聚集数据并创建层次结构
- Javascript-分层采样
- 如何从平面JavaScript数组创建分层HTML结构
- 如何使用 JavaScript 在分层结构上动态添加控件
- 如何将平面JavaScript对象数组转换为嵌套的分层JSON结构
- 分层结构中的并发分组操作
- 将平面结构转换为分层结构