Fra*_*Thu 2 javascript recursion json recursive-datastructures angularjs
我有以下 JSON。
[{
"ID": "Root_1",
"Name": "Root_1",
"ParentID": "",
"Sequent": 1
},
{
"ID": "Root_2",
"Name": "Root_2",
"ParentID": "",
"Sequent": 2
},
{
"ID": "Root_1_Sub_1_Child_1",
"Name": "Root_1_Sub_1_Child_1",
"ParentID": "Root_1_Sub_1",
"Sequent": 1
},
{
"ID": "Root_1_Sub_1_Child_2",
"Name": "Root_1_Sub_1_Child_2",
"ParentID": "Root_1_Sub_1",
"Sequent": 2
},
{
"ID": "Root_1_Sub_1",
"Name": "Root_1_Sub_1",
"ParentID": "Root_1",
"Sequent": 1
}]
Run Code Online (Sandbox Code Playgroud)
我想将我的 JSON 更改为如下。
[{
"ID": "Root_1",
"Name": "Root_1",
"ParentID": "",
"Sequent": 1,
"Sub": [{
"ID": "Root_1_Sub_1",
"Name": "Root_1_Sub_1",
"ParentID": "Root_1",
"Sequent": 1,
"Sub": [{
"ID": "Root_1_Sub_1_Child_1",
"Name": "Root_1_Sub_1_Child_1",
"ParentID": "Root_1_Sub_1",
"Sequent": 1
},
{
"ID": "Root_1_Sub_1_Child_2",
"Name": "Root_1_Sub_1_Child_2",
"ParentID": "Root_1_Sub_1",
"Sequent": 2
}]
}]
},
{
"ID": "Root_2",
"Name": "Root_2",
"ParentID": "",
"Sequent": 2
}]
Run Code Online (Sandbox Code Playgroud)
在我尝试以下方式后,结果不是我想要的。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="./bower_components/angular/angular.min.js"></script>
<script>
angular.module('myApp', [])
.controller('MyCtrl', function($scope, $http) {
$scope.ProjectCategoryList_FlatStyle = [{
"ID": "Root_1",
"Name": "Root_1",
"ParentID": "",
"Sequent": 1
},
{
"ID": "Root_2",
"Name": "Root_2",
"ParentID": "",
"Sequent": 2
},
{
"ID": "Root_1_Sub_1_Child_1",
"Name": "Root_1_Sub_1_Child_1",
"ParentID": "Root_1_Sub_1",
"Sequent": 1
},
{
"ID": "Root_1_Sub_1_Child_2",
"Name": "Root_1_Sub_1_Child_2",
"ParentID": "Root_1_Sub_1",
"Sequent": 2
},
{
"ID": "Root_1_Sub_1",
"Name": "Root_1_Sub_1",
"ParentID": "Root_1",
"Sequent": 1
}];
$scope.ProjectCategoryList_TreeStyle = [];
$scope.ParentArray = [];
$scope.ConvertFlatToTree = function(Value){
angular.forEach(Value, function(item){
// Create row.
var _Object = new Object();
_Object.ID = item.ID;
_Object.Name = item.Name;
_Object.ParentID = item.ParentID;
_Object.Sequent = item.Sequent;
_Object.Sub = [];
// Checking if it is root element.
if(item.ParentID){
// It is for child node.
// Get Parent Element.
var ParentElement = $scope.ParentArray.filter(function (x) { return x.ID === item.ParentID; });
ParentElement[0].Sub.push(_Object);
$scope.ParentArray.push(_Object);
}else{
// It is for parent node.
// Get child elements.
var ChildElementArray = $scope.ProjectCategoryList_FlatStyle.filter(function (x) { return x.ParentID === item.ID; });
if(ChildElementArray.length != 0){
$scope.ParentArray.push(_Object);
$scope.ProjectCategoryList_TreeStyle.push(_Object);
$scope.ConvertFlatToTree(ChildElementArray);
}
}
})
console.log("ProjectCategoryList_TreeStyle = ", JSON.stringify($scope.ProjectCategoryList_TreeStyle));
}
$scope.ConvertFlatToTree($scope.ProjectCategoryList_FlatStyle);
});
</script>
</head>
<body ng-app="myApp" ng-controller="MyCtrl">
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
下面是我的最终结果。
[{
"ID": "Root_1",
"Name": "Root_1",
"ParentID": "",
"Sequent": 1,
"Sub": [{
"ID": "Root_1_Sub_1",
"Name": "Root_1_Sub_1",
"ParentID": "Root_1",
"Sequent": 1,
"Sub": [{
"ID": "Root_1_Sub_1_Child_1",
"Name": "Root_1_Sub_1_Child_1",
"ParentID": "Root_1_Sub_1",
"Sequent": 1,
"Sub": []
},
{
"ID": "Root_1_Sub_1_Child_2",
"Name": "Root_1_Sub_1_Child_2",
"ParentID": "Root_1_Sub_1",
"Sequent": 2,
"Sub": []
}]
},
{
"ID": "Root_1_Sub_1",
"Name": "Root_1_Sub_1",
"ParentID": "Root_1",
"Sequent": 1,
"Sub": []
}]
}]
Run Code Online (Sandbox Code Playgroud)
这是您的解决方案。但是,如果您有更好的 ID 和 parentID 命名约定,情况会好得多。我没有进行大量的递归运行,而是先对输入数据进行排序,然后按顺序完成工作。
var flat = [{
"ID": "Root_1",
"Name": "Root_1",
"ParentID": "",
"Sequent": 1
},
{
"ID": "Root_2",
"Name": "Root_2",
"ParentID": "",
"Sequent": 2
},
{
"ID": "Root_1_Sub_1_Child_1",
"Name": "Root_1_Sub_1_Child_1",
"ParentID": "Root_1_Sub_1",
"Sequent": 1
},
{
"ID": "Root_1_Sub_1_Child_2",
"Name": "Root_1_Sub_1_Child_2",
"ParentID": "Root_1_Sub_1",
"Sequent": 2
},
{
"ID": "Root_1_Sub_1",
"Name": "Root_1_Sub_1",
"ParentID": "Root_1",
"Sequent": 1
}];
function nested(f){
return f.sort((a,b) => a.ID.length < b.ID.length ? 1 : a.ID.length == b.ID.length ? a.ID < b.ID ? -1 : 1 :-1)
.reduce((p,c,i,a) => {var parent = !!c.ParentID && a.find(e => e.ID === c.ParentID);
!!parent ? !!parent.Sub && parent.Sub.push(c) || (parent.Sub=[c]) : p.push(c);
return p;},[]);
};
document.write("<pre>" + JSON.stringify(nested(flat),null,2) + "</pre>");Run Code Online (Sandbox Code Playgroud)
好的,根据您的评论,当除了父母关系之外绝对没有任何信息时,我决定找到一个解决方案来嵌套一个平面阵列。我的意思是数组项属性可以是两种类型。
[{id: AY998, pid: FT497}, {id: SS113, pid: MN857}, {id: MN857, pid: "root"}, {id: FT497...
Run Code Online (Sandbox Code Playgroud)
其中id是元素的id,pid是父id,一些对象是root,没有其他信息,如级别等。
所以这个想法是根据父母的资历对数组进行排序,这意味着在孩子之后不会列出任何父母。因此,一旦完成排序,就可以通过反向迭代轻松完成嵌套。
好的,让我们创建一个包含 100 个此类性质的项目的混洗数组。(我实际上必须创建这样的代码来生成具有唯一 ID 和正确父母关系的项目数据数组。让我们看看代码
[{id: AY998, pid: FT497}, {id: SS113, pid: MN857}, {id: MN857, pid: "root"}, {id: FT497...
Run Code Online (Sandbox Code Playgroud)
所以它工作得很好而且很快。关键是排序算法。如前所述,它根据父母的资历对数组进行排序,并且没有孩子可以排在其父母之前。这是唯一的条件。但同时它准备了父 id 索引的 LUT(哈希列表),这样一旦我们开始反向迭代数组(从最后一项到第一项),它就可以避免我们对父项进行昂贵的搜索。相反,我们将从 LUT(查找表)对象向上查找它的索引,并插入它的子项(如果有)。非常快..!
所以这是你玩的repl.it。
| 归档时间: |
|
| 查看次数: |
2687 次 |
| 最近记录: |