扁平结构和树形结构的相互转化-php实现

1,787 阅读1分钟

扁平结构:

$items = array(
    5 => array('id' => 5, 'pid' => 2, 'name' => '鸡西市'),
    4 => array('id' => 4, 'pid' => 2, 'name' => '哈尔滨市'),
    1 => array('id' => 1, 'pid' => 0, 'name' => '江西省'),
    2 => array('id' => 2, 'pid' => 0, 'name' => '黑龙江省'),
    7 => array('id' => 7, 'pid' => 4, 'name' => '南岗区'),
    6 => array('id' => 6, 'pid' => 4, 'name' => '香坊区'),
    3 => array('id' => 3, 'pid' => 1, 'name' => '南昌市'),
    90 => array('id' => 100, 'pid' => 3, 'name' => '南昌市-县'),

);

通过引用的方式形成无限极分类树

/**
 * 通过引用的方式 生成无限级分类
 * 弊端,不能进行 分类结构的的格式化。
 * @param array $source
 * @param string $primaryKey
 * @param string $parentKey
 * @param string $childrenKey
 * @return array
 */
public function listToTreeByReference(array $source,$primaryKey = 'id', $parentKey = 'pid',$childrenKey = 'children')
{

    $tree = [];
    $newData = array_column($source,NULL,$primaryKey);
    foreach ($newData as $key => &$value) {
        if ($value[$parentKey] > 0) {
            //不是根节点的将自己的地址放到父级的child节点
            $newData[$value[$parentKey]][$childrenKey][] = &$value;
        } else {
            //根节点直接把地址放到新数组中
            $tree[] = &$newData[$value[$primaryKey]];

        }
    }
    return $tree;
}

如果需要格式化无限极分类树:

结构中增加了 level【当前层级】,path【当前节点路径】和isLeaf【当前节点是否是叶子结点】 字段。

/**
 * @param $data
 * @param int $id
 * @param int $level
 * @param array $path
 * @param string $pid
 * @param string $children
 * @return array
 */
function listToTreeByRecursion($data, $id = 0,$level = 1,$path = [],$pid = 'pid',$children = 'children'){
    //初始化儿子
    //初始化儿子
    $child = [];
    //循环所有数据找$id的儿子
    foreach ($data as $key => $datum) {
        $datum['isLeaf'] = false;
        //找到儿子了
        if ($datum[$pid] == $id) {
            //路径
            $datum['path']  = array_merge($path,array($id));
            //当前层级
            $datum['level'] = $level;
            //保存下来,然后继续找儿子的儿子
            $child[$datum['id']] = $datum;
            //先去掉自己,自己不可能是自己的儿孙
            unset($data[$key]);
            //递归找,并把找到的儿子放到一个child的字段中
            $child[$datum['id']][$children] = $this->listToTreeByRecursion($data, $datum['id'],$level + 1,$datum['path']);
            //归来,判断是否是叶子节点
            if(empty($child[$datum['id']][$children])){
                $child[$datum['id']]['isLeaf'] = true;
            }
        }
    }
    return array_values($child);
}

树形结构示例:

[
    {
        "id": 1,
        "pid": 0,
        "name": "江西省",
        "isLeaf": false,
        "path": [
            0
        ],
        "level": 1,
        "children": [
            {
                "id": 3,
                "pid": 1,
                "name": "南昌市",
                "isLeaf": false,
                "path": [
                    0,
                    1
                ],
                "level": 2,
                "children": [
                    {
                        "id": 100,
                        "pid": 3,
                        "name": "南昌市-县",
                        "isLeaf": true,
                        "path": [
                            0,
                            1,
                            3
                        ],
                        "level": 3,
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "id": 2,
        "pid": 0,
        "name": "黑龙江省",
        "isLeaf": false,
        "path": [
            0
        ],
        "level": 1,
        "children": [
            {
                "id": 5,
                "pid": 2,
                "name": "鸡西市",
                "isLeaf": true,
                "path": [
                    0,
                    2
                ],
                "level": 2,
                "children": []
            },
            {
                "id": 4,
                "pid": 2,
                "name": "哈尔滨市",
                "isLeaf": false,
                "path": [
                    0,
                    2
                ],
                "level": 2,
                "children": [
                    {
                        "id": 7,
                        "pid": 4,
                        "name": "南岗区",
                        "isLeaf": true,
                        "path": [
                            0,
                            2,
                            4
                        ],
                        "level": 3,
                        "children": []
                    },
                    {
                        "id": 6,
                        "pid": 4,
                        "name": "香坊区",
                        "isLeaf": true,
                        "path": [
                            0,
                            2,
                            4
                        ],
                        "level": 3,
                        "children": []
                    }
                ]
            }
        ]
    }
]

树形结构->扁平结构

 * @param  array $tree 原来的树
 * @param  string $children 孩子节点的键
 * @param  array  $list 过渡用的中间数组,
 * @return array
 */
function treeToList($tree, &$list = array(),$children = 'children')
{
    if(is_array($tree)) {
        foreach ($tree as  $value) {
            $refer = $value;
            if(!empty($refer[$children])){
                unset($refer[$children]);
                $this->treeToList($value[$children],$list);
            }
            $list[] = $refer;
        }
    }
    return $list;
}