如何基于点表示法和type属性将PHP扁平数组转换为树形数组
解决方法
核心逻辑:由于仅category_label类型的节点会包含子节点,我们可以先按节点层级深度升序排序,保证父节点先于子节点处理,再通过引用池存储可容纳子节点的分类节点,快速匹配插入即可。
以下是可直接运行的PHP代码:
function buildHierarchyTree(array $flatArray): array { // 按层级深度从小到大排序,确保父节点先被处理 usort($flatArray, function ($a, $b) { $depthA = count(explode('.', $a['hierarchy'])); $depthB = count(explode('.', $b['hierarchy'])); return $depthA <=> $depthB; }); $tree = []; $categoryRefs = []; // 存储所有分类节点的引用,key为对应hierarchy值 foreach ($flatArray as &$node) { // 初始化children字段,也可以仅给category_label类型的节点加 $node['children'] = []; $hierarchyParts = explode('.', $node['hierarchy']); $level = count($hierarchyParts); if ($level === 1) { // 根节点直接加入树结构 $tree[] = &$node; } else { // 计算父节点hierarchy值:去掉当前层级的最后一段 $parentHierarchy = implode('.', array_slice($hierarchyParts, 0, $level - 1)); // 找到对应父分类节点,插入到它的children中 if (isset($categoryRefs[$parentHierarchy])) { $categoryRefs[$parentHierarchy]['children'][] = &$node; } else { // 容错:找不到父分类时可自定义处理,比如加入根节点 $tree[] = &$node; } } // 仅分类节点存入引用池,供后续子节点匹配 if ($node['type'] === 'category_label') { $categoryRefs[$node['hierarchy']] = &$node; } } unset($node); // 解除引用,避免后续修改污染数据 return $tree; } // 测试调用 $array = [ [ "hierarchy" => "1", "title" => "Fruits", "type" => "category_label" ], [ "hierarchy" => "1.1", "title" => "Citruses", "type" => "category_label" ], [ "hierarchy" => "1.1.1", "title" => "Orange", "type" => "item" ], [ "hierarchy" => "1.1", "title" => "Mango", "type" => "item" ], [ "hierarchy" => "1.2", "title" => "Grape", "type" => "item" ] ]; $result = buildHierarchyTree($array); print_r($result);
逻辑说明
- 排序规则:按照
hierarchy按点拆分后的长度判断层级深度,深度越小越先处理,保证父节点在子节点之前被加载到引用池。 - 引用池作用:仅存储
category_label类型的节点,解决同hierarchy值下普通条目不会作为父节点的需求。 - 父节点匹配:当前节点去掉
hierarchy的最后一段即可得到父节点的hierarchy值,直接从引用池查找即可快速定位父节点。
运行上述代码得到的输出和你预期的树形结构完全一致。
内容的提问来源于stack exchange,提问作者asvp
相关产品推荐
相关产品推荐

