PHP实现扁平对象转层级对象的递归方法求助
解决扁平对象转层级结构的重复节点问题
你的问题核心在于原始递归代码会多次遍历整个数据集,导致同一个子节点被重复添加到父节点的children数组里。我们可以换一种更高效的方式——先通过ID索引所有节点,再一次性构建父子关系,从根源避免重复。
优化思路
- 用一个数组以节点ID为键缓存所有节点,这样能快速定位父节点,避免重复创建
- 遍历每个节点时,直接通过
parent值找到对应的父节点,将当前节点添加到父节点的children中 - 单独收集所有
parent=0的根节点,作为最终的层级结构返回
适配你场景的可行代码
<?php function unflatten ( $data ) { /* Create new node objects */ function create_new_node ( $o ) { return new class ( $o ) { public $id; public function __construct ( $o ) { // 保留节点除parent外的所有属性 foreach($o as $key => $value){ if ($key != 'parent'){ $this->$key = $value; } } } }; } $roots = array(); // 存储所有根节点(parent=0的节点) $nodes = array(); // 用ID做索引缓存所有节点,避免重复创建 foreach ( $data as $o ) { // 检查当前节点是否已缓存,没有则创建新节点 $node = isset( $nodes[$o->id] ) ? $nodes[$o->id] : create_new_node($o); $nodes[$o->id] = $node; // 更新节点缓存 if ( $o->parent != 0 ) { // 非根节点,找到父节点并关联 // 如果父节点还没缓存,先创建父节点对象 if ( !isset( $nodes[$o->parent] ) ) { $nodes[$o->parent] = create_new_node( $o ); } // 将当前节点添加到父节点的children数组中 if (!property_exists($nodes[$o->parent], 'children')) { $nodes[$o->parent]->children = []; } $nodes[$o->parent]->children[] = $node; } else { // 根节点直接加入根节点数组 $roots[] = $node; } } return $roots; } ?>
代码说明
create_new_node匿名类用于生成节点对象,自动过滤parent属性,保留其他所有字段$nodes索引数组确保每个节点只会被创建一次,彻底解决重复问题- 只有当父节点需要时才初始化
children属性,无子节点的节点不会生成冗余字段 - 仅遍历一次数据集即可完成层级构建,比反复递归遍历的效率提升明显
内容的提问来源于stack exchange,提问作者Richard V
相关产品推荐
相关产品推荐

