省市区多级联动数据组合

话不多说,直接说重点。最近用到了省市区数据联动。数据格式是这样的:

  $array = [
            0 => [
                'id' => 1,
                'pid' => 0,
                'name' => 't1',
            ],
            1 => [
                'id' => 2,
                'pid' => 0,
                'name' => 't2',
            ],
            2 => [
                'id' => 3,
                'pid' => 0,
                'name' => 't3',
            ],
            3 => [
                'id' => 4,
                'pid' => 1,
                'name' => 't1-t4',
            ],
            4 => [
                'id' => 5,
                'pid' => 2,
                'name' => 't2-t5',
            ],
            5 => [
                'id' => 6,
                'pid' => 4,
                'name' => 't1-t4-t6',
            ],
        ];

返回格式要求是这样的:

 Array
(
    [0] => Array
        (
            [id] => 1
            [pid] => 0
            [name] => t1
            [child] => Array
                (
                    [0] => Array
                        (
                            [id] => 4
                            [pid] => 1
                            [name] => t1-t4
                            [child] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 6
                                            [pid] => 4
                                            [name] => t1-t4-t6
                                        )

                                )

                        )

                )

        )

    [1] => Array
        (
            [id] => 2
            [pid] => 0
            [name] => t2
            [child] => Array
                (
                    [0] => Array
                        (
                            [id] => 5
                            [pid] => 2
                            [name] => t2-t5
                        )

                )

        )

    [2] => Array
        (
            [id] => 3
            [pid] => 0
            [name] => t3
        )

)

在知道数组层级且层级比较少的情况下,最简单粗暴的方式当然是多层遍历组装数组。但是这样显然有点 low。来说三种比较洋气的方式。

递归

首先想到的当然是递归。递归的本质也是遍历循环,效率应该相差不多,但是代码量明显减少,看起来清爽了很多。

    function getOptionsTree($array, $pid = 0)
    {
        $optionsTree = [];
        foreach ($array as $key => $item){
            //假设从根节点开始,pid 为0,将根节点元素放入数组
            if ($item['pid'] == $pid){
                $optionsTree[$item['id']] = $item;
                //销毁已查询的,减轻下次递归查询数量
                unset($array[$key]);
                //递归开始,查询根节点的子类,并将其元素放入根节点下的 child 中
                $optionsTree[$item['id']]['child'] = $this->getOptionsTree($array, $item['id']);
            }
        }

        return $optionsTree;
    }

栈递归

该方法暂时只能处理2层数据,后期待优化。但是重点不是这个方法,而是利用栈来解决问题的思路。该方法利用了栈 先进后出,即后进先出 的特点,通过入栈、出栈来达到数据组合的目的。

   function getTreeOptions($array, $pid = 0)
    {
        $tree = [];
        if (!empty($array)) {
            //先取出顶级的来压入数组$stack中,并将在$list中的删除掉
            $stack = [];
            foreach ($array as $key => $value) {
                if ($value['pid'] == $pid) {
                    array_push($stack,$value);
                    unset($array[$key]);
                }
            }

            while (count($stack)) {
                //先从栈中取出第一项
                $info = array_pop($stack);
                if ($info['pid'] == 0){
                    $tree[$info['id']] = $info;
                }else{
                    $tree[$info['pid']]['child'][$info['id']] = $info;
                }

                //查询剩余的$list中pid与其id相等的,也就是查找其子节点
                foreach ($array as $key => $child) {
                    if ($child['pid'] == $info['id']) {
                        //如果有子节点则入栈,while循环中会继续查找子节点的下级
                        array_push($stack,  $child);
                        unset($array[$key]);
                    }
                }
            }
        }
        return $tree;
    }

引用

首推方法。引用赋值,就是说将赋值左边的直接指向内存中存储这个值的这块区域,如 $b = &$a,$a 和 $b 在内存中指向的值的区域是相同的,因此当这块区域的值被改变,两个变量都会被改变。

明白这一点,这个方法也就可以看明白了。

    function getTreeOptions($list, $pid = 0)
    {
        $tree = [];
        if (!empty($list)) {
            //先修改为以id为下标的列表
            $newList = [];
            foreach ($list as $k => $v) {
                $newList[$v['id']] = $v;
            }
            //然后开始组装成特殊格式
            foreach ($newList as $value) {
                if ($pid == $value['pid']) {//先取出顶级
                    $tree[] = &$newList[$value['id']];
                } elseif (isset($newList[$value['pid']])) {//再判定非顶级的pid是否存在,如果存在,则再pid所在的数组下面加入一个字段items,来将本身存进去
                    $newList[$value['pid']]['child'][] = &$newList[$value['id']];
                }
            }
        }
        return $tree;
    }

好文章要分享:

https://www.cnblogs.com/vishun/p/6716483.html

原文地址:https://www.cnblogs.com/suojian/p/13964955.html