PHP:将具有path属性的数组转换为树结构

时间:2015-10-22 18:04:31

标签: php arrays

让我们说,我有以下数组:

$array = array(
    array(
        "id"   => 1,
        "name" => "Europe",
        "path" => "/"
    ),
    array(
        "id"   => 2,
        "name" => "Germany",
        "path" => "/1/"
    ),
    array(
        "id"   => 3,
        "name" => "France",
        "path" => "/1/"
    ),
    array(
        "id"   => 4,
        "name" => "Berlin",
        "path" => "/1/2/"
    ),
    array(
        "id"   => 5,
        "name" => "Munich",
        "path" => "/1/2/"
    )
);

正如你所看到的,它是一个多维数组,在earch第二级数组中有3个属性:id,name和path。路径是基于其父级的父标识的路径结构。例如,德国(id = 2)属于欧洲,因此路径为" / 1 /" (身份证1 =欧洲)德国的柏林有路径" / 1/2 /"这意味着" /欧洲/德国/"

现在,我正在尝试创建一个树形数组,它应该看起来像:

$result = array(
    1 => array(
        "id" => 1,
        "name" => "Europe",
        "path" => "/",
        "childs" => array(
            2 => array(
                "id" => 2,
                "name" => "Germany",
                "path" => "/1/",
                "childs" => array(
                    4 => array(
                        "id"   => 4,
                        "name" => "Berlin",
                        "path" => "/1/2/"
                    ),
                    5 => array(
                        "id"   => 5,
                        "name" => "Munich",
                        "path" => "/1/2/"
                    )
                )
            ),
            3 => array(
                "id"   => 3,
                "name" => "France",
                "path" => "/1/"
            )
        )
    )
);

我已经尝试使用内部引用创建一个函数,但这对我没有用:

public static function pathToTree($items) {
    $array = array();
    $result = array();

    foreach($items AS $res) {
        $ids = explode("/", ltrim($res["path"] . $res["id"], "/"));
        $count = count($ids);
        $tmp = &$result;

        foreach( $ids AS $id) {
            if($count == 1) {
                $tmp = $res;
                $tmp["childs"] = array();
                $tmp = &$tmp["childs"];
            }
            else {
                $tmp[$id] = array(
                    "childs" => array()
                );
                $tmp = &$tmp[$id]["childs"];
            }
            $count--;
        }
    }

    return $array;
}

3 个答案:

答案 0 :(得分:0)

正如我在评论中所说,你需要至少三个循环来实现你的目标。这是功能:

function pathToTree($array){
    $tree = Array();
    for($i=0; $i < count($array); $i++){
        if(substr_count($array[$i]["path"], '/') == 1)
            $tree[$array[$i]["id"]] = $array[$i];
    }
    for($i=0; $i < count($array); $i++){
        if(substr_count($array[$i]["path"], '/') == 2){
            $num = (int)str_replace("/","",$array[$i]["path"]);
            $tree[$num]["childs"][$array[$i]["id"]] = $array[$i];
        }
    }
    for($i=0; $i < count($array); $i++){
        if(substr_count($array[$i]["path"], '/') == 3){
            $num = explode("/", $array[$i]["path"]);
            $tree[$num[1]]["childs"][$num[2]]["childs"][$array[$i]["id"]] = $array[$i];
        }
    }
    return $tree;
}

示例:

考虑这个数组:

$array = array(
    array(
        "id"   => 1,
        "name" => "Europe",
        "path" => "/"
    ),
    array(
        "id"   => 2,
        "name" => "Germany",
        "path" => "/1/"
    ),
    array(
        "id"   => 3,
        "name" => "France",
        "path" => "/1/"
    ),
    array(
        "id"   => 4,
        "name" => "Berlin",
        "path" => "/1/2/"
    ),
    array(
        "id"   => 5,
        "name" => "Munich",
        "path" => "/1/2/"
    ),
    array(
        "id"   => 6,
        "name" => "Asia",
        "path" => "/"
    ),
    array(
        "id"   => 7,
        "name" => "China",
        "path" => "/6/"
    ),
    array(
        "id"   => 8,
        "name" => "Bangladesh",
        "path" => "/6/"
    ),
    array(
        "id"   => 9,
        "name" => "Beijing",
        "path" => "/6/7/"
    ),
    array(
        "id"   => 10,
        "name" => "Dhaka",
        "path" => "/6/8/"
    )
);

如果我运行此代码:

print_r(pathToTree($array));

输出将是:

Array
(
    [1] => Array
        (
            [id] => 1
            [name] => Europe
            [path] => /
            [childs] => Array
                (
                    [2] => Array
                        (
                            [id] => 2
                            [name] => Germany
                            [path] => /1/
                            [childs] => Array
                                (
                                    [4] => Array
                                        (
                                            [id] => 4
                                            [name] => Berlin
                                            [path] => /1/2/
                                        )

                                    [5] => Array
                                        (
                                            [id] => 5
                                            [name] => Munich
                                            [path] => /1/2/
                                        )

                                )

                        )

                    [3] => Array
                        (
                            [id] => 3
                            [name] => France
                            [path] => /1/
                        )

                )

        )

    [6] => Array
        (
            [id] => 6
            [name] => Asia
            [path] => /
            [childs] => Array
                (
                    [7] => Array
                        (
                            [id] => 7
                            [name] => China
                            [path] => /6/
                            [childs] => Array
                                (
                                    [9] => Array
                                        (
                                            [id] => 9
                                            [name] => Beijing
                                            [path] => /6/7/
                                        )

                                )

                        )

                    [8] => Array
                        (
                            [id] => 8
                            [name] => Bangladesh
                            [path] => /6/
                            [childs] => Array
                                (
                                    [10] => Array
                                        (
                                            [id] => 10
                                            [name] => Dhaka
                                            [path] => /6/8/
                                        )

                                )

                        )

                )

        )

)

以下是phpfiddle link,以防您自己尝试。

答案 1 :(得分:0)

好的,我想我刚刚找到了解决方案:

function pathToTree($array){
    $tree = array();
    foreach($array AS $item) {
        $pathIds = explode("/", ltrim($item["path"], "/") . $item["id"]);
        $current = &$tree;
        foreach($pathIds AS $id) {
            if(!isset($current["childs"][$id])) $current["childs"][$id] = array();
            $current = &$current["childs"][$id];
            if($id == $item["id"]) {
                $current = $item;
            }
        }
    }
    return $tree["childs"];
}

这是1-n深度的动力解决方案。看看我在http://ideone.com/gn0XLp的例子。在这里,我测试了一些水平:

  1. 国家
  2. 市区
  3. 市街道
  4. 城市分区

答案 2 :(得分:0)

我创建了一个递归函数:

//数组

$array = array(
    array(
        "id"   => 1,
        "name" => "Europe",
        "path" => "/"
    ),
    array(
        "id"   => 2,
        "name" => "Germany",
        "path" => "/1/"
    ),
    array(
        "id"   => 3,
        "name" => "France",
        "path" => "/1/"
    ),
    array(
        "id"   => 4,
        "name" => "Berlin",
        "path" => "/1/2/"
    ),
    array(
        "id"   => 5,
        "name" => "Munich",
        "path" => "/1/2/"
    ),
    array(
        "id"   => 6,
        "name" => "Asia",
        "path" => "/"
    ),
    array(
        "id"   => 7,
        "name" => "India",
        "path" => "/6/"
    ),
    array(
        "id"   => 7,
        "name" => "Mumbai",
        "path" => "/6/7"
    ),
    array(
        "id"   => 8,
        "name" => "Delhi",
        "path" => "/6/7"
    ),
);

//递归函数

function createTree($input, &$result = array(), $key = null) {
    if ($key == "id") {
        $result["temp"]["id"] = $input;
    }
    if ($key == "name") {
        $result["temp"]["name"] = $input;
    }
    if ($key == "path") {
        $result["temp"]["path"] = $input;
        $levels = is_string($input) ? array_values(array_filter(explode('/', $input))) : null;
        if ($input == "/") {
            $result[$result["temp"]["id"]] = $result["temp"];
        }
        if (count($levels) == 1) {
            $result[$levels[0]]["childs"][$result["temp"]["id"]] = $result["temp"];
        }
        if (count($levels) == 2) {
            $result[$levels[0]]["childs"][$levels[1]]["childs"][$result["temp"]["id"]] = $result["temp"];
        }
        unset($result["temp"]);
    }
    if (is_array($input)) {
        foreach($input as $key => $value) {
            createTree($value, $result, $key);
        }
    }
    return $result;
}

//结果

array (
  1 => 
  array (
    'id' => 1,
    'name' => 'Europe',
    'path' => '/',
    'childs' => 
    array (
      2 => 
      array (
        'id' => 2,
        'name' => 'Germany',
        'path' => '/1/',
        'childs' => 
        array (
          4 => 
          array (
            'id' => 4,
            'name' => 'Berlin',
            'path' => '/1/2/',
          ),
          5 => 
          array (
            'id' => 5,
            'name' => 'Munich',
            'path' => '/1/2/',
          ),
        ),
      ),
      3 => 
      array (
        'id' => 3,
        'name' => 'France',
        'path' => '/1/',
      ),
    ),
  ),
  6 => 
  array (
    'id' => 6,
    'name' => 'Asia',
    'path' => '/',
    'childs' => 
    array (
      7 => 
      array (
        'id' => 7,
        'name' => 'India',
        'path' => '/6/',
        'childs' => 
        array (
          7 => 
          array (
            'id' => 7,
            'name' => 'Mumbai',
            'path' => '/6/7',
          ),
          8 => 
          array (
            'id' => 8,
            'name' => 'Delhi',
            'path' => '/6/7',
          ),
        ),
      ),
    ),
  ),
)