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

PHP实现从子节点向上遍历父节点生成逗号分隔分类字符串

问题:从嵌套分类JSON中根据子节点ID生成向上遍历的路径字符串

你有一个abc.json文件,结构如下:

{ 
  "meta": { 
    "code": 200, 
    "requestId": "5afd9043dd57977f0f88d3b1" 
  }, 
  "response": { 
    "categories": [ 
      { 
        "id": "1", 
        "categories": [ 
          { "id": "a", "categories": [] }, 
          { 
            "id": "b", 
            "categories": [ 
              { "id": "c", "categories": [] }, 
              { 
                "id": "d", 
                "categories": [
                  { "id": "e", "categories": [] }, 
                  { "id": "f", "categories": [] } 
                ] 
              } 
            ] 
          } 
        ] 
      }, 
      { 
        "id": "2", 
        "categories": [ 
          { "id": "i", "categories": [] }, 
          { 
            "id": "j", 
            "categories": [ 
              { "id": "k", "categories": [] }, 
              { "id": "l", "categories": [] } 
            ] 
          } 
        ] 
      } 
    ] 
  } 
}

需求是:指定子节点ID时,生成从根到该节点的路径字符串(比如指定c得到'1,b,c',指定i得到'2,i')。你尝试的递归代码没有达到预期效果,下面我来帮你实现正确的方案。


解决方案1:递归直接查找路径

这个方法适合单次查找的场景,递归遍历分类树的同时记录当前路径,找到目标节点时直接返回完整路径。

完整代码示例

// 读取并解析JSON文件
$jsonContent = file_get_contents('abc.json');
$data = json_decode($jsonContent, true);
$rootCategories = $data['response']['categories'];

/**
 * 递归查找目标节点的路径
 * @param array $categories 当前遍历的分类列表
 * @param string $targetId 要查找的节点ID
 * @param array $currentPath 当前已遍历的路径
 * @return string|null 找到的路径字符串,未找到则返回null
 */
function findCategoryPath($categories, $targetId, $currentPath = []) {
    foreach ($categories as $category) {
        // 将当前节点ID加入临时路径
        $tempPath = $currentPath;
        $tempPath[] = $category['id'];
        
        // 找到目标节点,返回拼接后的路径
        if ($category['id'] === $targetId) {
            return implode(',', $tempPath);
        }
        
        // 如果当前节点有子分类,递归查找
        if (!empty($category['categories'])) {
            $result = findCategoryPath($category['categories'], $targetId, $tempPath);
            // 子节点找到结果,直接返回
            if ($result !== null) {
                return $result;
            }
        }
    }
    // 遍历完未找到目标,返回null
    return null;
}

// 测试调用
echo findCategoryPath($rootCategories, 'c'); // 输出:1,b,c
echo "\n";
echo findCategoryPath($rootCategories, 'i'); // 输出:2,i

代码说明

  • 函数会遍历每个分类节点,把当前节点ID加入临时路径;
  • 如果当前节点就是目标ID,直接将路径数组转为逗号分隔的字符串返回;
  • 如果当前节点有子分类,就递归传入子分类、目标ID和当前临时路径;
  • 一旦递归找到结果,就立即返回,避免不必要的遍历。

解决方案2:构建父节点映射表(适合多次查找)

如果需要多次查询不同节点的路径,先构建一个「节点ID => 父节点ID」的映射表,之后从目标节点向上追溯父节点,最后反转路径得到结果,效率更高。

完整代码示例

// 读取并解析JSON文件
$jsonContent = file_get_contents('abc.json');
$data = json_decode($jsonContent, true);
$rootCategories = $data['response']['categories'];

/**
 * 构建节点与父节点的映射表
 * @param array $categories 当前遍历的分类列表
 * @param string|null $parentId 当前分类的父节点ID
 * @param array &$map 存储映射关系的数组(引用传递)
 */
function buildParentMap($categories, $parentId = null, &$map = []) {
    foreach ($categories as $category) {
        $map[$category['id']] = $parentId;
        // 递归处理子分类
        if (!empty($category['categories'])) {
            buildParentMap($category['categories'], $category['id'], $map);
        }
    }
}

/**
 * 根据映射表生成目标节点的路径
 * @param string $targetId 要查找的节点ID
 * @param array $parentMap 节点-父节点映射表
 * @return string|null 路径字符串,未找到则返回null
 */
function getPathFromMap($targetId, $parentMap) {
    if (!isset($parentMap[$targetId])) {
        return null;
    }
    
    $path = [];
    $currentId = $targetId;
    // 从目标节点向上追溯所有父节点
    while ($currentId !== null) {
        $path[] = $currentId;
        $currentId = $parentMap[$currentId] ?? null;
    }
    // 反转路径(因为是从子到父收集的)
    return implode(',', array_reverse($path));
}

// 构建映射表
$parentMap = [];
buildParentMap($rootCategories);

// 测试调用
echo getPathFromMap('c', $parentMap); // 输出:1,b,c
echo "\n";
echo getPathFromMap('i', $parentMap); // 输出:2,i

代码说明

  • buildParentMap函数遍历整个分类树,把每个节点的父ID存入映射数组;
  • getPathFromMap函数从目标节点开始,顺着映射表向上找所有父节点,收集到路径数组后反转,再转为字符串。

为什么你之前的代码没生效?

你之前的displayRec函数只是递归遍历了节点,但没有记录路径,也没有返回找到的结果,所以无法生成并返回你需要的路径字符串。上面的两种方案都解决了这两个核心问题。

内容的提问来源于stack exchange,提问作者Saswat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:17:51