在平时工作中, 经常需要将普通列表数据, 处理成树, 列表数据结构大致如下:
+----+--------------+-----+
| id | name | pid |
+----+--------------+-----+
| 1 | 媒体(白名单) | 0 |
| 2 | 党媒公共平台 | 0 |
| 3 | 政府机构 | 0 |
| 4 | 其他 | 0 |
| 5 | 中央媒体 | 1 |
| 6 | 地方媒体 | 1 |
| 7 | 门户媒体 | 4 |
| 8 | 综合媒体 | 4 |
| 9 | 专业媒体 | 4 |
| 11 | 河北省 | 6 |
| 12 | 山东省 | 6 |
| 13 | 辽宁省 | 6 |
| 34 | 北京 | 6 |
| 45 | 视频 | 9 |
| 46 | 教育 | 9 |
| 79 | 法律 | 9 |
| 80 | 其他 | 9 |
| 81 | 文学 | 9 |
+----+--------------+-----+
常规实现方式是使用递归模式, 但是在笔者工作中, 需要处理很大的数据量, 使用递归, 会严重影响性能, 而用<b>一次循环方式也可以很好的处理</b>在处理大数据量时, 性能会提示非常多
完整代码如下
<?php
header('Content-Type:application/json;charset=UTF-8');
$src = '[{"id":"1","name":"媒体(白名单)","pid":"0"},{"id":"2","name":"党媒公共平台","pid":"0"},{"id":"3","name":"政府机构","pid":"0"},{"id":"4","name":"其他","pid":"0"},{"id":"5","name":"中央媒体","pid":"1"},{"id":"6","name":"地方媒体","pid":"1"},{"id":"7","name":"门户媒体","pid":"4"},{"id":"8","name":"综合媒体","pid":"4"},{"id":"9","name":"专业媒体","pid":"4"},{"id":"11","name":"河北省","pid":"6"},{"id":"12","name":"山东省","pid":"6"},{"id":"13","name":"辽宁省","pid":"6"},{"id":"34","name":"北京","pid":"6"},{"id":"45","name":"视频","pid":"9"},{"id":"46","name":"教育","pid":"9"},{"id":"79","name":"法律","pid":"9"},{"id":"80","name":"其他","pid":"9"},{"id":"81","name":"文学","pid":"9"}]';
$result = json_decode($src, true);
echo json_encode(listToTree($result), JSON_UNESCAPED_UNICODE);
/**
* 核心函数, 将列表数据转化树形结构
* 使用前提必须是先有父后有子, 即儿子的id必须小于父亲id
* 列表数据必须安装id从小到大排序
* @param $lists 原始列表数据
* @param string $childKey 字段名
* @return array 返回树形数据
*/
function listToTree($lists, $childKey = 'children'){
$map = [];
$res = [];
foreach($lists as $id => &$item){
// 获取出每一条数据的父id
$pid = &$item['pid'];
// 将每一个item的引用保存到$map中
$map[$item['id']] = &$item;
// 如果在map中没有设置过他的pid, 说明是根节点, pid为0,
if(!isset($map[$pid])){
// 将pid为0的item的引用保存到$res中
$res[$id] = &$item;
}else{
// 如果在map中没有设置过他的pid, 则将该item加入到他父亲的叶子节点中
$pItem = &$map[$pid];
$pItem[$childKey][] = &$item;
}
}
return $res;
}
最终处理结果如下: