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

如何优化从混合分类列表提取品牌的递归函数?

优化品牌分类提取的性能方案

现有一个混合品牌与分类的列表categories,示例如下:

categories = [
      # 品牌相关
      { "id": "brands", "parentCategoryId": None },
      { "id": "ls", "parentCategoryId": "brands" },
      { "id": "bleed", "parentCategoryId": "brands" },
      { "id": "shape", "parentCategoryId": "brands" },
      { "id": "graze", "parentCategoryId": "brands" },
      { "id": "item", "parentCategoryId": "brands" },
      { "id": "install", "parentCategoryId": "brands" },
      { "id": "horror", "parentCategoryId": "brands" },
      { "id": "thanks", "parentCategoryId": "brands" },
      { "id": "scrape", "parentCategoryId": "brands" },
      { "id": "shelter", "parentCategoryId": "brands" },
      { "id": "dynamic", "parentCategoryId": "brands" },
      { "id": "under", "parentCategoryId": "shape" },
      { "id": "right", "parentCategoryId": "shape" },
      { "id": "base", "parentCategoryId": "shape" },
      { "id": "scrap", "parentCategoryId": "shape" },
    
      # 分类相关
      { "id": "root", "parentCategoryId": None },
      { "id": "bark", "parentCategoryId": "rich" },
      { "id": "rich", "parentCategoryId": "sting" },
      { "id": "rich", "parentCategoryId": "sting" },
      { "id": "sting", "parentCategoryId": "root" },
    ]

需求是提取所有父节点链最终指向id为"brands"的根节点的对象。

原实现采用递归判断每个对象的父链,但每次查找父节点都需要遍历整个列表,当数据量达到数百条时,重复遍历导致性能低下,原代码如下:

brands = []

def getParent(id):
  for obj in categories:
    if obj['id'] == id:
      return obj

def is_brand(obj):
  if obj['id'] == 'brands' and obj['parentCategoryId'] == None:
    return True
  
  if obj['id'] == 'root':
    return False
  
  if not obj['parentCategoryId'] == None:
    return is_brand(getParent(obj['parentCategoryId']))


for obj in categories:
  if is_brand(obj):
    brands.append(obj)

print(brands)

优化方案

方案一:预构建映射+从根节点遍历收集

核心思路是先把所有对象按ID存入字典实现O(1)查找,再从"brands"根节点出发,通过广度优先或深度优先遍历所有子节点,一次性收集所有品牌相关对象。

# 第一步:构建ID到对象的映射字典,O(n)时间
id_to_obj = {obj['id']: obj for obj in categories}

# 第二步:构建父ID到子对象列表的映射
parent_to_children = {}
for obj in categories:
    parent_id = obj['parentCategoryId']
    if parent_id not in parent_to_children:
        parent_to_children[parent_id] = []
    parent_to_children[parent_id].append(obj)

# 第三步:从brands根节点开始广度遍历所有子节点
brands = []
queue = [id_to_obj['brands']]

while queue:
    current = queue.pop(0)  # 广度优先用pop(0),深度优先用pop()
    brands.append(current)
    # 把当前节点的所有子节点加入队列
    if current['id'] in parent_to_children:
        queue.extend(parent_to_children[current['id']])

print(brands)

方案二:带缓存的判断函数

如果需要保留逐个判断的逻辑,可以给is_brand函数添加缓存,避免重复判断同一个节点,同时用字典映射优化父节点查找。

# 构建ID到对象的映射
id_to_obj = {obj['id']: obj for obj in categories}
# 缓存已判断的节点结果
cache = {}

def is_brand(obj):
    obj_id = obj['id']
    # 先查缓存,避免重复计算
    if obj_id in cache:
        return cache[obj_id]
    
    if obj_id == 'brands' and obj['parentCategoryId'] is None:
        cache[obj_id] = True
        return True
    
    if obj_id == 'root':
        cache[obj_id] = False
        return False
    
    parent_id = obj['parentCategoryId']
    if parent_id is None:
        # 非brands/root的根节点,不属于品牌
        cache[obj_id] = False
        return False
    
    parent_obj = id_to_obj.get(parent_id)
    if not parent_obj:
        # 父节点不存在,标记为非品牌
        cache[obj_id] = False
        return False
    
    result = is_brand(parent_obj)
    cache[obj_id] = result
    return result

brands = [obj for obj in categories if is_brand(obj)]
print(brands)

优化说明

  • 字典映射优化:将原O(n)的父节点查找降低为O(1),大幅减少遍历次数
  • 根节点遍历方案:仅遍历品牌相关的节点,无需处理所有分类节点,时间复杂度从O(n²)降到O(n)
  • 缓存机制:避免重复判断同一个节点的父链,尤其适用于存在大量共享父节点的场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:05:34