【记一次遗忘的树形处理逻辑】
最近在小论文数据展示中,刚好我使用的echat插件来展示本体树结构,但是这个插件所需要的数据是树形数据,数据格式如下:
{
"name": "flare",
"children": [
{
"name": "data",
"children": [
{
"name": "converters",
"children": [
{"name": "Converters", "value": 721},
{"name": "DelimitedTextConverter", "value": 4294}
]
},
{
"name": "DataUtil",
"value": 3322
}
]
},
{
"name": "display",
"children": [
{"name": "DirtySprite", "value": 8833},
{"name": "LineSprite", "value": 1732},
{"name": "RectSprite", "value": 3623}
]
},
{
"name": "flex",
"children": [
{"name": "FlareVis", "value": 4116}
]
}
]
}
处理方法A
这时候的第一想法就是使用递归,递归算法要求的源数据的格式为:['id'=> 1, name='第一个节点','pid'=>'父级节点'] ,每一个节点的记录格式都是这样的即可满足树形数组的构建。代码逻辑:
$data = [
[
'id' => 1,
'name' => '菜单一',
'pid' => 0
],
[
'id' => 11,
'name' => '菜单一点一',
'pid' => 1
],
[
'id' => 12,
'name' => '菜单一点二',
'pid' => 1
],
[
'id' => 13,
'name' => '菜单一点三',
'pid'=>1
],
[
'id' => 2,
'name' => '菜单二',
'pid' => 0
],
[
'id' => 21,
'name' => '菜单二点一',
'pid' => 2
],
[
'id' => 111,
'name' => '菜单一点一点一',
'pid' => 11
],
[
'id' => 112,
'name' => '菜单一点一点二',
'pid' => 11
],
[
'id' => 113,
'name' => '菜单一点一点三',
'pid' => 11
],
[
'id' => 121,
'name' => '菜单一点二点一',
'pid' => 12
],
[
'id' => 1111,
'name' => '菜单一点一点一点一',
'pid' => 111
],
[
'id' => 1112,
'name' => '菜单一点一点一点二',
'pid' => 111
]
];
$parent = [];
getTree($parent,0,$data);
echo json_encode($parent['children'],256);
/**
* 建立树形结构
* @param $parent
* @param $id
* @param $data
*/
function getTree(&$parent, $id, $data){
$child = getChildren($id,$data);
if(!empty($child)){
$i = 0;
foreach ($child as $item){
$parent['children'][$i] = $item;
//依靠当前父节点的索引,来向下继续传递父级:$parent['children'][$i]
getTree($parent['children'][$i],$parent['children'][$i]['id'],$data);
$i++;
}
}
}
/**
* 获取孩子节点
* @param $id
* @param $data
* @return array
*/
function getChildren($id, $data){
$child = [];
foreach ($data as $item){
if($item['pid'] == $id){
$child[] = $item;
}
}
return $child;
}
注释:依照先跟遍历的想法,依次找孩子,找孩子的孩子,往下找孩子的时候,传入父亲的地址,之后回溯找下一个孩子,找下一个孩子的孩子,最后即完成树形的构建。
处理方法B
使用非递归的方式也可以解决问题,只不过非递归的方式要求数据源格式需要含有层级关系,即为该节点是第几层级的节点,数据源的格式为:['id'=> 1, name='第一个节点',level='1', 'pid'=>'父级节点'],按照层级进行降序排列,然后先封装最底层的,然后依次往上层组装孩子节点。 代码逻辑:$data = [
[
'id' => 1,
'name' => '菜单一',
'pid' => 0,
'level' => 1
],
[
'id' => 11,
'name' => '菜单一点一',
'pid' => 1,
'level' => 2
],
[
'id' => 12,
'name' => '菜单一点二',
'pid' => 1,
'level' => 2
],
[
'id' => 13,
'name' => '菜单一点三',
'pid'=>1,
'level' => 2
],
[
'id' => 2,
'name' => '菜单二',
'pid' => 0,
'level' => 1
],
[
'id' => 21,
'name' => '菜单二点一',
'pid' => 2,
'level' => 2
],
[
'id' => 111,
'name' => '菜单一点一点一',
'pid' => 11,
'level' => 3
],
[
'id' => 112,
'name' => '菜单一点一点二',
'pid' => 11,
'level' => 3
],
[
'id' => 113,
'name' => '菜单一点一点三',
'pid' => 11,
'level' => 3
],
[
'id' => 121,
'name' => '菜单一点二点一',
'pid' => 12,
'level' => 3
],
[
'id' => 1111,
'name' => '菜单一点一点一点一',
'pid' => 111,
'level' => 4
],
[
'id' => 1112,
'name' => '菜单一点一点一点二',
'pid' => 111,
'level' => 4
]
];
//进行排序
function sortByLevel(&$data){
foreach ($data as $item){
$flag[] = $item['level'];
}
array_multisort($flag,SORT_DESC,$data);
}
//进行建树
function createTree($data){
$nodeLevelList = [];
foreach ($data as $key => &$item){
$children = isset($nodeLevelList[$item['id']]['children']) ? $nodeLevelList[$item['id']]['children'] : [];
//如果孩子不为空的话
if(!empty($children)){
//合并自己的孩子
$item = array_merge($item,['children'=>$children]);
}
//如果不是定级的话
if($item['pid'] !=0){
//指定父级的孩子为自己下的数组
$nodeLevelList[$item['pid']]['children'][] = $item;
//释放掉自己所占资源
unset($nodeLevelList[$item['id']]);
}else{
//如果节点是定级,就不能再找父级,到此结束
$nodeLevelList[$item['id']] =$item;
}
}
return $nodeLevelList;
}
sortByLevel($data);
$tree = createTree($data);
echo json_encode($tree,256);