从 PHP 中的平面路径数组构建目录树

Posted

技术标签:

【中文标题】从 PHP 中的平面路径数组构建目录树【英文标题】:Build directory tree from flat array of paths in PHP 【发布时间】:2019-07-11 09:26:20 【问题描述】:

所以,标题可能令人困惑,但我不知道如何措辞这种数组结构。它肯定是一个树结构,但至于它的创建,这就是我渴望的地方。它似乎没有遵循原型递归数组树的构建。

我正在尝试从一个平面路径数组创建一个列目录布局,每个路径都在它自己的多维数组中。

该数组旨在构建一个macOS Finder列视图样式界面,使用FinderJS如下(来自下面的数据):

| elections   > | id                    |           |            |
|               | name                  |           |            |
|               | description         > | field     |            |
|               | dynamic_parent_id   > | field     |            |
|               | method              > | field   > | field_more |

该库需要一个 'item' 对象数组,在 JS 中,格式如下:

[
    label: 'elections',
    children: [
        label: 'id'
    , 
        label: 'name'
    , 
        label: 'description',
        children: [
            label: 'field'
        ]
    , 
        label: 'dynamic_parent_id',
        children: [
            label: 'field'
        ]
    , 
        label: 'method',
        children: [
            label: 'field',
            children: [
                label: 'field_more'
            ]
        ]
    ]
]

我正在尝试从以下 php 数组中获取上述内容,该数组名为 $fields

Array
(
    [0] => Array
        (
            [0] => elections
            [1] => id
        )

    [1] => Array
        (
            [0] => elections
            [1] => name
        )

    [2] => Array
        (
            [0] => elections
            [1] => description
            [2] => field
        )

    [3] => Array
        (
            [0] => elections
            [1] => dynamic_parent_id
            [2] => field
        )

    [4] => Array
        (
            [0] => elections
            [1] => method
            [2] => field
            [3] => field_more
        )

...[and so forth]...
];

需要将其改造成如下结构,允许发生 json_encode 并传递给客户端进行加载:

Array
(
    [0] => Array
        (
            [label] => elections
            [children] => Array
                (
                    [0] => Array
                        (
                            [label] => id
                            [children] => Array
                                (
                                )
                        )
                    [1] => Array
                        (
                            [label] => name
                            [children] => Array
                                (
                                )
                        )
                    [2] => Array
                        (
                            [label] => description
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [label] => field
                                            [children] => Array
                                                (
                                                )
                                        )
                                )
                        )
                    [3] => Array
                        (
                            [label] => dynamic_parent_id
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [label] => field
                                            [children] => Array
                                                (
                                                )
                                        )
                                )
                        )
                    [4] => Array
                        (
                            [label] => method
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [label] => field
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [label] => field_more
                                                            [children] => Array
                                                                (
                                                                )
                                                        )
                                                )
                                        )
                                )
                        )
                )
        )
)
... and so forth ...
];

我尝试创建查找数组来计算和存储父键,以便在另一个构建循环期间按所需的结构级别进行查找,但这也不起作用。

我尝试重新分解循环以最初基于级别构建树,但意识到必须递归才能首先构建子数组或逐级查看该项目之前是否已经存在在所述级别上生成。

表面上看起来相当简单,因为您在每个级别构造一个数组,但是检查“目录”是否存在于该级别,如果存在,请输入它,然后检查下一个级别项目是否存在于该级别,如果没有则创建,然后输入该数组。我假设递归地执行最后一部分,按照每条路径所需的次数沿着链向下执行。

但在这一点上,我尝试过的所有途径都已经用尽,我有点卡在这个脑筋急转弯上。任何帮助将不胜感激!

到目前为止,我所拥有的最好的是我制作的这个小树生成器,但仅适用于每个分支。我需要另一个循环,我假设在 1 级获取所有键并将它们合并在一起,与 2、3 等相同...

function buildTree(array $branches): array

    if (count($branches)) 
        $branches = array_values($branches);
        $newBranch = $branches[0];
        unset($branches[0]);

        return [
            'label' => $newBranch,
            'children' => $this->buildTree($branches)
        ];
     else 
        return [];
    


foreach ($fields as $field) 
    $treePieces[] = $this->buildTree($field);


print_r($treePieces);

给出以下输出:

Array
(
    [0] => Array
        (
            [label] => elections
            [children] => Array
                (
                    [label] => id
                    [children] => Array
                        (
                        )
                )
        )
    [1] => Array
        (
            [label] => elections
            [children] => Array
                (
                    [label] => name
                    [children] => Array
                        (
                        )
                )
        )
    [2] => Array
        (
            [label] => elections
            [children] => Array
                (
                    [label] => description
                    [children] => Array
                        (
                        )
                )
        )
... and so forth ...
)

它是如此接近,但由于明显的原因并不完全存在,如果父级已经存在,它就不会向下遍历目录。它遵循典型的树结构吗?我觉得有,但我看不出来……

【问题讨论】:

【参考方案1】:

您可以分两步完成:

创建关联数组的层次结构,其中标签是键,嵌套数组对应于子数组。 将该结构转换为目标结构

代码:

function buildTree($branches) 
    // Create a hierchy where keys are the labels
    $rootChildren = [];
    foreach($branches as $branch) 
        $children =& $rootChildren;
        foreach($branch as $label) 
            if (!isset($children[$label])) $children[$label] = [];
            $children =& $children[$label];
        
    
    // Create target structure from that hierarchy
    function recur($children) 
        $result = [];
        foreach($children as $label => $grandchildren) 
            $node = ["label" => $label];
            if (count($grandchildren)) $node["children"] = recur($grandchildren);
            $result[] = $node;
        
        return $result;
    
    return recur($rootChildren);

这样称呼它:

$tree = buildTree($branches);

当没有孩子时,上面会省略children 键。如果您在这些情况下也需要 children 键,则只需删除 if (count($grandchildren)) 条件,并简化为以下版本:

function buildTree($branches) 
    // Create a hierchy where keys are the labels
    $rootChildren = [];
    foreach($branches as $branch) 
        $children =& $rootChildren;
        foreach($branch as $label) 
            if (!isset($children[$label])) $children[$label] = [];
            $children =& $children[$label];
        
    
    // Create target structure from that hierarchy
    function recur($children) 
        $result = [];
        foreach($children as $label => $grandchildren) 
            $result[] = ["label" => $label, "children" => recur($grandchildren)];
        
        return $result;
    
    return recur($rootChildren);

【讨论】:

这工作......完美!太感谢了!!!确保通读并理解它。非常聪明,也值得记住!

以上是关于从 PHP 中的平面路径数组构建目录树的主要内容,如果未能解决你的问题,请参考以下文章

php 在PHP中使用平面数组构建树

从平面对象数组构建对象树数组[重复]

JAVA目录树

PHP从遍历嵌套树模型构建数组

从对象树构造平面数组

7-30 目录树