php递归生成树

2018年6月6日 2 作者 筱枫

最近开发过程中遇到一个小问题,要求将一些数据转换为树形结构,类似于

[
    'name' => 'root',
    'children' => [
        [
            'name' => 'first',
            'children' => [
                [
                    'name' => 'first-first',
                    'children' => []
                ],
                [
                    'name' => 'first-two',
                    'children' => []
                ],],
        ],
        [
            'name' => 'two',
            'children' => [
                [
                    'name' => 'two-first',
                    'children' => []
                ],
                [
                    'name' => 'two-two',
                    'children' => []
                ],],
        ]
    ]];

提供的数据结构是这种类型

看上去是个树形结构,再结合前面的数据格式,所以脑海中很简单的就冒出了方法——用递归。

虽然之前写过一些递归,但真正用于这种项目还是头一次,当中也是遇到不少错误,所以算法以及数据结构扎实还是很有必要的。

关于递归之类的定义就不多说了,简单来说就是分而治之,大事化小,小事化了这种,所以,我们从最简单的开始考虑,这里采用的是自底向上的方式建立树

1.如何处理  最后一列的数据,即将其变为一个数组

看上面这个数据结构,似乎有点头疼?没关系,只要忽略掉其他不必要的东西就行

现在,数据结构在我们眼中是这个样子

现在,问题是不是一下子简单起来?

那么,这是我的代码

$data = '
电话沟通
电子邮件沟通
短信沟通
移动平台沟通
其他沟通方式';

$data = explode("\r\n", $data);

$newData = [];
foreach ($data as $v)
{
    $newData[] = [
        'name' => $v,
        'children' => []
    ];
}

print_r($newData);

特别注意其中的”\r\n”,不要使用单引号,单引号当中的数据是不会被转义的

php的数组十分强大,所以这里我将其分割为数组,方便处理,接着就是日常操作了,跑个循环就出来了

2.第二步,如何处理有级联的

现在,我们眼中的数据结构是这样的

如何处理?继续用for循环?似乎有点难处理,那么,这个时候就是递归的出现了

或许你会有其他、更好的想法, 但是我的代码是这样的

/**
 * @param $data
 * @param $index
 * @return array
 */
function recursive(&$data, $index)
{
    $temp = [];

    while (true)
    {
        $str = next($data);

        if (!$str)
            return $temp;

        $currentIndex = 0;

        $str = str_replace("\t", '', $str, $currentIndex);

        if ($currentIndex <= $index)
        {
            prev($data);
            return $temp;
        }

        $temp[] = [
            'children' => recursive($data, $currentIndex),
            'name' => $str,
        ];
    }
}

$data = '
沟通方式
   电话沟通
   电子邮件沟通
   短信沟通
   移动平台沟通
   其他沟通方式
销售方式';

$data = explode("\r\n", $data);

print_r(recursive($data, -1));

突然有些头大?那就对了——容我慢慢道来

首先如何解决读取数据的问题?

在这里我通过php数组自带的next和prev控制着数组,来获取每条数据

接着,替换掉前面tab符号,currentIndex用于记录是第几级,整个函数最重要的部分是这段

if ($currentIndex <= $index)
{
prev($data);
return $temp;
}


这段用于第三级别与第二级之间的过渡,如果不使用prev($data);

那么 “其他沟通方式”的children 中就会包含 “销售方式

造成层级不对,之后就是递归的常规操作,调用自己
其中你可能注意到,最开始调用的时候传递的index 是 -1

print_r(recursive($data, -1));

这样可以可以防止第一个 沟通方式 被跳过

如此,可能会比较绕,但逻辑上还是挺清晰的,建议有迷惑的同学可以自己断点,一步步查看

点此下载源码