将路径数组转换为树

时间:2018-11-15 14:29:35

标签: php


我想转换路径名称数组,例如

add_header "Foo-Header-Value" "$sent_http_foo";

插入树数组。上面示例的匹配树数组为:

$paths = ["foo/bar/lorem", "foo/bar/ipsum", "foo/dolor"];

我知道,这并不难,但是PHP对按引用传递与按值传递的处理使我很挣扎。

谢谢。

编辑:我认为这不是重复的,就像您提到的线程中那样,有给定的父ID。

到目前为止我所做的事情:

$tree = [
    [
        "name" => "foo",
        "children" => [
            [
                "name" => "bar",
                "children" => [
                    [
                        "name" => "lorem",
                        "children" => []
                    ],
                    [
                        "name" => "ipsum",
                        "children" => []
                    ]
                ]
            ],
            [
                "name" => "dolor",
                "children" => []
            ]
        ]
    ]
];

但这给了我公正的待遇

private function buildTree()
{
    $paths = [
        "foo/bar/lorem",
        "foo/bar/ipsum",
        "foo/dolor",
    ];

    $tree = [];

    foreach ($paths as $path) {
        $parts = explode("/", $path);

        $currentLevel = &$tree;

        foreach ($parts as $part) {
            $existingPath = $this->findByName($currentLevel, $part);
            if ($existingPath) {
                $currentLevel = &$existingPath["children"];
            } else {
                $newPart = [
                    "name" => $part,
                    "children" => [],
                ];

                $currentLevel[] = $newPart;
                $currentLevel = &$newPart["children"];
            }
        }
    }

    return $tree;
}

private function findByName(&$array, $name) {
    foreach($array as &$item) {
        if (strcmp($item["name"], $name) === 0) {
            return $item;
        }
    }
    return false;
}

3 个答案:

答案 0 :(得分:2)

这可以解决问题,但请继续投票:

private function buildTree()
{
    $paths = [
        "foo/bar/lorem",
        "foo/bar/ipsum",
        "foo/dolor",
    ];

    $tree = [];

    foreach ($paths as $path) {
        $level = &$tree;

        $parts = explode("/", $path);

        foreach($parts as $part) {
            if (!$this->findByName($level, $part)) {
                $level[] = [
                    "name" => $part,
                    "children" => []
                ];
            }

            $level = &$level[count($level)-1]["children"];
        }
    }

    return $tree;
}

private function findByName(&$array, $name) {
    foreach($array as &$item) {
        if (strcmp($item["name"], $name) === 0) {
            return $item;
        }
    }
    return false;
}

答案 1 :(得分:2)

非常类似于您所拥有的,但是使用一些内置函数来查找要添加到...的元素。

function buildTree()
{
    $paths = [
        "foo/bar/lorem",
        "foo/bar/ipsum",
        "foo/dolor",
    ];

    $tree = [];

    foreach ($paths as $path) {
        $parts = explode("/", $path);
        $node = &$tree;
        foreach ( $parts as $level )   {
            $newNode = array_search ($level, array_column($node, "name")??[]);
            if ( $newNode === false ) {
                $newNode = array_push( $node, [ "name" => $level, "children" => []]) -1;
            }
            $node = &$node[$newNode]["children"];
        }
    }

    return $tree;
}

print_r(buildTree());

答案 2 :(得分:1)

对不起,我参加比赛很晚,但这是使用递归函数的另一种解决方案:

<?php
$paths = array("foo/bar/lorem", "foo/bar/ipsum", "foo/dolor");

$test = [];

foreach($paths as $path){
    $splitPath = preg_split('/\//', $path);
    addChild($test, $splitPath);
}

function addChild(&$arr, &$splitPath){
    $parent = array_shift($splitPath);
    //check for $parent in $test array
    $foundParent = 0;
    foreach($arr as &$item){
        if($item['name'] == $parent){
            if(count($splitPath) > 0){addChild($item['children'], $splitPath);}
            $foundParent = 1;
        }
    }
    //if not found, add to array
    if($foundParent == 0){
        $arr[] = array('name' => $parent,'children' => []);
        if(count($splitPath) > 0){addChild($arr[count($arr)-1]['children'], $splitPath);}
    }
}

print_r($test);

?>