You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:17:52