0
点赞
收藏
分享

微信扫一扫

php 无限极分类循环拼接数组

方法1:

 public function get_tree($data, $pid = 0, $level = 0) {
static $tree = array();
static $ppp = array();
foreach ($data as $key => $row) {
if ($row['spread_uid'] == $pid) {
$row['level'] = $level;

if(isset($data[$pid])){
$data[$pid] = $data[$pid];
}
$ppp[$pid]['children'][] = $row;
$tree[] = $row;
unset($data[$key]); //进入树结构后,接下里要查的就只是它的子类了,所以从$data中删除,减少后面查询次数
$this->get_tree($data, $row['uid'], $level + 1);
}
}
return $ppp;
}

方法二:

/**
* 生成树形结构数据
* @param $items 以数组形式存储的处理目标数据
* @param $parentId 父节点的ID
* @return array
*/
function generateTree($items , $parentId) {
// 初始化一个数组,用以存储输出数据
$tree = array();
/* 遍历数组,对数据递归处理*/
foreach($items as $k => $v) {

/* 判断当前节点的parentId是否与参数相同?
* 如果相同,沿着同父节点向下递归。进一步
* 判断当前节点的子节点是否不为空,如果不
* 为空,将当前节点归入当前父节点的children中
*/
if(isset($v['parent_id']) && $v['parent_id'] == $parentId) {
if($v['level']!=4){//只有省和地级市才有下级子节点
$set = generateTree($items , $v['id']);
if (!empty($set)) {
$v['children'] = generateTree($items , $v['id']);
}
// $v['children'] = generateTree($items , $v['id']);
}
unset($v['parent_id']);//较少输出字段,提高接口速度
$tree[] = $v;
}
}
return $tree;
}

//数据太多,只输出一些基础数据,取消关联,否会会很慢
/*
$sql = "
SELECT
ld.id,
ld.parent_id,
ld.admincode,
ld.name,
lde.simple_name,
ld.lng,
ld.lat,
ld.level
FROM
lbs_district ld
LEFT JOIN lbs_district_extends lde ON ld.id = lde.lbs_district_id
WHERE
ld.is_foreign = 1
AND ld.level IN (2,3,4)
ORDER BY ld.id ASC";
*/
$sql = "
SELECT
ld.id,
ld.parent_id,
ld.name,
ld.lng,
ld.lat,
ld.level
FROM
lbs_district ld
WHERE
ld.is_foreign = 1
AND ld.level IN (2,3,4)
ORDER BY ld.id ASC";

$return = $db->getAll($sql);
// 接口要求获取国内省、市、区县三级行政区划树形结构,所以根节点取中国行政区划ID
$treeRes = generateTree($return, '8008600000000000000');
echo json_encode($treeRes);;
$db->close();

?>
————————————————
原文链接:https://blog.csdn.net/lbq15735104044/article/details/125070839


方法3:

 public function trees($listsa , $parentId){
//pp($items);
$items = array();
foreach ($listsa as $k => $v) {
$items[$v['uid']] = $v;
}

$tree = array();
foreach ($items as $kk => $vv) {
if(isset($items[$vv['spread_uid']])){
$items[$vv['spread_uid']]['son'][] = &$items[$kk];
}else{
$tree[] = &$items[$kk];
}
}
return $tree;

}

解释说明:

说到无限极分类,比较常见的做法是在建表的时候,增加一个PID字段用来区别自己所属的分类 

php 无限极分类循环拼接数组_数据

由于展示数据的时候,需要表达出这种所属关系,所以必然要在读取数据的时候进行一系列处理,由此就牵涉到了两种算法

国民级算法——递归

从数据库取得​​二维数组​​省略,递归的思路其实很简单,遍历数组,根据每条数据的id值去寻找所有pid值等于自己id值的数据,直到找不到为止,实际实现起来也是通俗易懂

function getTree($arr,$pid=0,$level=0)
{
static $list = [];
foreach ($arr as $key => $value) {
if ($value["auth_pid"] == $pid) {
$value["level"] = $level;
$list[] = $value;
unset($arr[$key]); //删除已经排好的数据为了减少遍历的次数,当然递归本身就很费神就是了
getTree($arr,$value["id"],$level+1);
}
}
return $list;
}

基本也没啥好说的,这里返回去的是一个已经排序好的一维数组,展示的时候直接​​遍历​​就好,加入level字段是为了展示的时候,如果需要缩进,可以有个依据

巧妙的引用算法

上面的递归原理通俗易懂,但是总所周知的原因,递归对资源的消耗是非常大的,实际执行起来效率也很低,所以有了下面的通过引用算法

function generateTree($data){
$items = array();
foreach($data as $v){
$items[$v['auth_id']] = $v;
}
$tree = array();
foreach($items as $k => $item){
if(isset($items[$item['auth_pid']])){
$items[$item['auth_pid']]['son'][] = &$items[$k];
}else{
$tree[] = &$items[$k];
}
}
return $tree;
}

是不是感觉有点谜之晕,慢慢分析这一段代码, 整个方法大体分成两个部分 ,第一部分是

   $items = array();
foreach($data as $v){
$items[$v['auth_id']] = $v;
}

​这一段应该是很通俗的,就是构建一个新的数组,新数组的key值是自己的主键id值 

进行完这一步之后,应该得到的数组形式是这样额

Array
(
[100] => Array
(
[auth_id] => 100
[auth_name] => 后台首页
[auth_pid] => 0
)

[116] => Array
(
[auth_id] => 116
[auth_name] => 管理员
[auth_pid] => 0
)

[120] => Array
(
[auth_id] => 120
[auth_name] => 管理员列表
[auth_pid] => 116
)

[121] => Array
(
[auth_id] => 121
[auth_name] => 管理员添加
[auth_pid] => 116
)

[122] => Array
(
[auth_id] => 122
[auth_name] => 数据一览
[auth_pid] => 100
)

[123] => Array
(
[auth_id] => 123
[auth_name] => 更新日志
[auth_pid] => 100
)
)

至于为什么要特地多一次遍历来将数组的KEY值重构,这里就是第二部分的巧妙之处了

 $tree = array();
foreach($items as $k => $item){
if(isset($items[$item['auth_pid']])){
$items[$item['auth_pid']]['son'][] = &$items[$k];
}else{
$tree[] = &$items[$k];
}
}
return $tree;

慢慢的分析一下,这段代码将已经重构的数组遍历 

并判断当前数组元素的父级分类是否存在 

举个例子 foreach第一次循环的时候

$k = 100;
$item = Array
(
[auth_id] => 100
[auth_name] => 后台首页
[auth_pid] => 0
)
$items[$item['auth_pid']] = $items[0]; //不存在键值为0的数组元素,证明是顶级分类
isset($items[$item['auth_pid']]) = false;
$tree[] = &$items[$k];

注意到这里,是采取引用的方式,为什么呢?因为后面,其实我们的数组元素是会变化的 

当foreach第三次循环的时候,同样分析

$k = 120;
$item = Array
(
[auth_id] => 120
[auth_name] => 管理员列表
[auth_pid] => 116
)
$items[$item['auth_pid']] = $items[116];
isset($items[$item['auth_pid']]) = true; //存在键值为116的数组元素,证明这个元素是键值116元素的子分类
$items[$item['auth_pid']]['son'][] = &$items[$k];//给键值为116的数组元素增加一个son键,并将当前遍历的这个元素赋值给这个键

这里也是采取了引用,还是那个原因,因为当前遍历的元素很有可能还有子分类,当有子分类的时候,按照这个算法,他自己还要增加son这个键,所以采用引用赋值的方式,可以保证自己的结构是完美的

整体来看这个算法,如果加上两句输出来看一下

 $tree = array();
foreach($items as $k => $item){
if(isset($items[$item['auth_pid']])){
$items[$item['auth_pid']]['son'][] = &$items[$k];
echo "1111<br>";
}else{
echo "2222<br>";
$tree[] = &$items[$k];
}
}

那么会得到这样的结果

2222
2222
1111
1111
1111
1111

可以看到,其实$tree里面只有两个数组元素,而这两个数组元素是带有son键的,在son键里面保存着自己的所有后代元素 
进行完这个算法之后,得到的结果会是这样的

 
Array
(
[0] => Array
(
[auth_id] => 100
[auth_name] => 后台首页
[auth_pid] => 0
[son] => Array
(
[0] => Array
(
[auth_id] => 122
[auth_name] => 数据一览
[auth_pid] => 100
)
[1] => Array
(
[auth_id] => 123
[auth_name] => 更新日志
[auth_pid] => 100
)
)
)
[1] => Array
(
[auth_id] => 116
[auth_name] => 管理员
[auth_pid] => 0
[son] => Array
(
[0] => Array
(
[auth_id] => 120
[auth_name] => 管理员列表
[auth_pid] => 116
)
[1] => Array
(
[auth_id] => 121
[auth_name] => 管理员添加
[auth_pid] => 116
)
)
)
)

这个结果可以很方便的采用json的方式返回给前台,或者接下来采用递归的方式使其变成一维数组,都是很方便的,整个方法的精妙处就在于引用的使用

虽然这个例子使用的只有二级分类,实际上无论几级分类都是很完美的,而且在运行速度上可以说都是很快的,从时间复杂度来说只是一个for循环,比递归好使

举报

相关推荐

0 条评论