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

时间:2019-07-11 09:26:20

标签: php arrays tree

因此,标题可能令人困惑,但是我不确定如何用这种数组结构来表达。当然,这是一个树形结构,但是对于它的创建,这就是我渴望的地方。它似乎没有遵循原型递归数组树的构建。

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

此数组旨在使用FinderJS来构建macOS Finder列视图样式界面,如下所示(来自以下数据):

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

该库需要使用以下示例格式的JS数组“ item”对象:

[{
    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'
            }]
        }]
    }]
}]

我正在尝试从以下名为$fields的PHP数组中获取以上内容:

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 个答案:

答案 0 :(得分: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);
}