如何将Laravel的allDirectories()输出转换为层级目录树多维数组
问题描述
首先我已经查阅了所有能找到的相关资源示例,但是没找到足够贴合的方案来解决这个问题,尽管问题看起来并不复杂。我还看到有一个相同的同类问题至今没有得到解决,我的场景和该问题完全一致,因此直接使用相同的示例数据。
我调用Laravel的allDirectories()函数得到的输出大致如下:
array:20 [▼ 0 => "test" 1 => "files" 2 => "files/2" 3 => "files/2/Blocks" 4 => "files/2/Blocks/thumbs" 5 => "files/shares" ]
我希望将其转换为如下格式的多维数组:
[ ["label" => "test", "path" => "test", "children" => []], ["label" => "files", "path" => "files", "children" => [ ["label" => "2", "path" => "files/2", "children" => [ ["label" => "Blocks", "path" => "files/2/Blocks", "children" => [ [ "label" => "thumbs", "path" => "files/2/Blocks/thumbs", "children" => [] ] ] ] ] ], ["label" => "shares", "path" => "files/shares", "children" => []] ] ], ];
请问要如何操作才能将allDirectories()的输出转换为上述结构的多维数组?
解决方案
你可以通过路径分层遍历+引用映射的方式实现转换,核心逻辑是先处理短路径(父目录)再处理长路径(子目录),用映射表快速定位父节点位置,避免递归遍历查找损耗。
完整实现代码如下:
// 第一步:获取allDirectories返回的路径数组,替换为你自己的路径获取逻辑 $directories = Storage::allDirectories(); // 第二步:按路径长度排序,保证父目录一定比子目录先处理 usort($directories, function($a, $b) { return strlen($a) - strlen($b); }); $tree = []; // 路径映射表,存储每个路径对应的节点引用,方便快速查找 $pathMap = []; foreach ($directories as $path) { // 拆分路径段 $segments = explode('/', $path); // 当前节点的标签是最后一个路径段 $label = end($segments); $currentNode = [ 'label' => $label, 'path' => $path, 'children' => [] ]; // 根目录(没有父路径)直接加到根树 if (count($segments) === 1) { $tree[] = $currentNode; // 把当前节点的引用存到映射表 $pathMap[$path] = &$tree[count($tree) - 1]; } else { // 取出父路径:去掉最后一个路径段再拼接 array_pop($segments); $parentPath = implode('/', $segments); // 父节点肯定已经在映射表中(因为提前做了排序) $parentNode = &$pathMap[$parentPath]; // 把当前节点加到父节点的children数组 $parentNode['children'][] = $currentNode; // 把当前节点的引用存到映射表 $pathMap[$path] = &$parentNode['children'][count($parentNode['children']) - 1]; } // 解除引用,避免后续循环变量覆盖导致异常 unset($currentNode); } // 最终$tree就是你需要的结构 dd($tree);
逻辑说明
- 路径排序是核心前提,保证父目录处理时子目录还未处理,父节点已经存在于映射表中
- 引用映射表避免了每次查找父节点都要遍历整棵树,处理大量目录时效率更高
- 代码兼容任意层级的目录嵌套,不需要提前知道目录深度
内容的提问来源于stack exchange,提问作者Marcel
相关产品推荐
相关产品推荐

