原始数据
-
数据库
原始数据
-
打印到页面
原始数据
递归
- 递归的思路就是【找儿子】,也就是循环所有数据,找到每条数据的所有儿子、儿子的儿子、儿子的儿子的儿子....,首先我们知道要找test1的儿子就是找所有pid为1的数据,于是遍历整个数组找到了test1-1和test1-2;然后还要分别找test1-1和test1-2的儿子,就这样一直找下去,由于每次找儿子的方法都是一样的,就是遍历所有数据(除开自己的长辈,因为长辈不可能是儿孙),找出符合条件的,唯一不同的就是每次找儿子的爹不一样,代码如下:
function getChild($data, $id = 0)
{
//初始化儿子
$child = [];
//循环所有数据找$id的儿子
foreach ($data as $key => $datum) {
//找到儿子了
if ($datum['pid'] == $id) {
//保存下来,然后继续找儿子的儿子
$child[$datum['id']] = $datum;
//先去掉自己,自己不可能是自己的儿孙
unset($data[$key]);
//递归找,并把找到的儿子放到一个child的字段中
$child[$datum['id']]['child'] = $this->getChild($data, $datum['id']);
}
}
return $child;
}
运行结果:
引用
-
引用确实是一个非常巧妙的方法,也不用像递归那样循环那么多次,思路就是首先把所有数据以id为索引重新排列,排列之后长这个样子:
重排之后的数据
- 然后重点来啦!!!然后只需要找到根节点,也就是pid是0的三条数据,把它们放到一个全新的数组中,注意:这里的放并不是简单的赋值,而是引用之前的地址。这两者有什么不同呢,这里简单几个例子说明一下:
function test(){
$a=1;
$b=$a; //赋值
$b1=&$a;//赋址
$a=2;
dump('$b的值是:'.$b);
dump('$b1的值是:'.$b1);
}
最开始$a
初始化为1,把$a
的值(也就是1)赋给变量$b
,然后把$a
的地址(内存地址)赋给$b1
,然后改变$a
的值,再查看$b
和$b
的值。结果如下:
我们发现
$b
的值还是1,而$b1
的值却跟随着$a
的改变而改变了,这就是因为$b
保存的是$a
的地址,无论$a
怎么变他们的值都会保持一致。回到我们之前的问题上来,我们用新的数组保存了根节点的地址,后面无论根节点怎么变我们的新数组都会和变化过后的数据保持一致;那么不是根节点的数据怎么处理呢,我们这里可以把它的地址放到他爹的儿子节点当中,这样的话就是一层层引用,最后所有的数据都被新数组引用了。
说了这么多,代码如下:
function getChild($data)
{
$tree = [];
$newData = [];
//循环重新排列
foreach ($data as $datum) {
$newData[$datum['id']] = $datum;
}
foreach ($newData as $key => $datum) {
if ($datum['pid'] > 0) {
//不是根节点的将自己的地址放到父级的child节点
$newData[$datum['pid']]['child'][] = &$newData[$key];
} else {
//根节点直接把地址放到新数组中
$tree[] = &$newData[$datum['id']];
}
}
return $tree;
}
运行结果:
网友评论