开发中遇到的递归问题总结(数据的特点有个parentId,主要是把parentId相同的数据整合成tree的要求)

本文总结了在Vue.js项目中,利用ElementUI的Tree组件处理具有parentId特性的数据,将这些数据转换为树形结构的需求。在页面模板和数据处理方法中,详细阐述了如何整合并展示这些数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在vue项目中使用elementUI的tree处理后端返回的数据:数据的特点有个parentId,主要是把parentId相同的数据整合成tree的要求,然后把数据结构在页面中显示出来。

 function generateTree (origin, list) {
    let _tree = [] // 下一次递归用到的父节点列表
    let _arr = [] // 未匹配父节点的列表
    list.forEach(item => {
      let hadPush = false // 用于判断 item 是否已经成功匹配父节点
      origin.forEach(elem => {
        // 判断 id 和 parentId 的关系
        if (elem.id == item.parentId) { // 匹配父节点
          item.children = []
          elem.children.push(item) // 放入 tree
          _tree.push(item) // 放入父节点列表,下次递归用到
          hadPush = true
        }
      })
      // 未成功匹配父节点,放到 _arr
      !hadPush && _arr.push(item)
    })
    // 判断是否还有未匹配的节点,如果有,继续递归,如果没有,则退出递归
    if (_arr.length) {
      this.generateTree(_tree, _arr)
    }
  }

在vue页面中使用来处理数据:

       // 查询文件夹列表
        getFloderList (cb) {
          if (this.floderList && this.floderList.length) {
            cb.call(this, this.floderList)
          } else {
            collectApi.Getfolder().then(resp => {
              if (resp && resp.code == 200) {
                let tree = [] // 解析后的结果
                let _arr = [] // 第一次遍历剩余的数组
                resp.data.forEach((item, index) => {
                  if (item.parentId == 0) {
                    item.children = []
                    tree.push(item)
                    let obj = {
                      label: item.folderName,
                      id: item.id,
                      isleaf: false,
                      children:  generateTree(tree, _arr)
                    }
                  } else {
                    _arr.push(item)
                  }
                })
                generateTree(tree, _arr)
                this.floderList = tree
              } else {
                this.$message.error(resp.msg)
              }
            })
          }
        },

页面模板:

          <el-tree :data="floderList" :props="defaultProps" @node-click="handleNodeClick">
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <span>
                <svg class="icon" aria-hidden="true">
                  <use xlink:href="#icon-Files"></use>
                </svg>{{ node.label }}
              </span>
            </span>
          </el-tree>

data里面定义的数据

          defaultProps: {
            children: 'children',
            label: 'folderName'
          },

方法里面定义:

        handleNodeClick (item) {
          this.floderList.forEach(i => {
            i.check = false
          })
          item.check = true
          this.currentFloder = item
          this.$set(this.floderList, item)
        },
<think>嗯,用户现在的问题是关于如何将列表数据转换为树形结构。之前他们遇到了SQL查询结果重复的问题,现在可能是在处理BOM(物料清单)或类似的分层数据。用户给出的数据结构有ParentID、ParentName、ChildID和Path,需要整理树形结构。首先,我需要确定用户的使用场景,可能是前端展示、数据导出或者进一步的数据处理。他们可能是一个开发人员,正在处理数据库查询结果,需要将扁平的数据结构转换树形结构以便于显示或分析。 接下来,我需要考虑用户的真实需求。用户可能希望了解如何通过编程方法(比如Python或JavaScript)来递归构建树,或者是否可以使用SQL直接生成树形结构。此外,用户提到的Path字段可能已经包含了层级信息,但需要确认其格式,比如是否是类似“1.2.3”这样的路径,或者是其他形式。如果是的话,可能可以利用Path来辅助构建树形结构,而不需要完全依赖递归查询。 另外,用户之前的问题涉及到递归查询导致的重复数据,所以在处理树形结构时,需要避免循环引用,确保数据没有重复节点。可能需要检查数据中的环状结构,或者确保ParentID和ChildID的关系是严格层级的。同时,用户可能需要了解如何高效地处理大数据量的情况,比如使用哈希表(字典)来快速查找父节点,从而优化构建过程。 用户可能还关心如何展示树形结构,比如生成JSON格式、缩进文本或者在前端使用组件展示。需要给出具体的代码示例,例如Python中使用字典和递归函数,或者JavaScript中的对象处理。此外,解释每一步的逻辑,比如如何建立父子关系映射,如何递归构建子树,以及如何处理根节点等。 还需要考虑数据中的根节点如何标识,比如ParentID为null或某个特定值。如果数据中没有明确的根节点,可能需要先找出所有没有父节点的项作为根,然后递归构建子树。同时,Path字段的存在可能简化这一过程,如果Path字段已经反映了完整的层级路径,可以直接解析路径来构建树,而不需要递归查找父节点。 最后,用户可能需要验证生成的树形结构是否正确,比如检查每个节点是否出现在正确的位置,子节点是否完整,以及是否有循环引用。提供调试方法或验证步骤会更有帮助,比如输出树的深度、节点数量,或者使用可视化工具检查结构。</think>--- 要将包含 `ParentID`, `ParentName`, `ChildID`, `Path` 的列表数据整理为树形结构,**核心逻辑是通过递归或迭代建立父子关系映射**。以下是 **分步实现方法** 和 **关键代码示例**: --- ### **一、数据结构分析(示例)** 假设原始数据如下: ```python data = [ {"ParentID": None, "ParentName": "Root", "ChildID": "A", "Path": "A"}, {"ParentID": "A", "ParentName": "NodeA", "ChildID": "B", "Path": "A.B"}, {"ParentID": "A", "ParentName": "NodeA", "ChildID": "C", "Path": "A.C"}, {"ParentID": "B", "ParentName": "NodeB", "ChildID": "D", "Path": "A.B.D"} ] ``` --- ### **二、构建树形结构的核心步骤** #### **1. 建立节点映射关系** ```python def build_tree(data): # 创建节点字典:{ChildID: 节点对象} node_map = {item["ChildID"]: {"id": item["ChildID"], "name": item["ParentName"], "children": []} for item in data} # 添加根节点(ParentID为空的节点) root = None for item in data: if item["ParentID"] is None: root = node_map[item["ChildID"]] break # 建立父子关系 for item in data: parent_id = item["ParentID"] child_id = item["ChildID"] if parent_id in node_map: node_map[parent_id]["children"].append(node_map[child_id]) return root ``` #### **2. 处理结果(Python示例)** 调用函数后得到嵌套结构: ```python { "id": "A", "name": "Root", "children": [ { "id": "B", "name": "NodeA", "children": [{"id": "D", "name": "NodeB", "children": []}] }, {"id": "C", "name": "NodeA", "children": []} ] } ``` --- ### **三、扩展优化技巧** #### **1. 利用 Path 字段加速构建** 如果 `Path` 字段明确层级(如 `A.B.C`): ```python def build_tree_by_path(data): tree = {} for item in sorted(data, key=lambda x: len(x["Path"])): path_parts = item["Path"].split('.') current_level = tree for part in path_parts[:-1]: current_level = current_level.setdefault(part, {}).setdefault("children", {}) current_level[path_parts[-1]] = {"id": item["ChildID"], "name": item["ParentName"]} return tree ``` #### **2. 避免循环引用检测** 在数据预处理阶段检查环状结构: ```python def has_cycle(data): visited = {} for item in data: path = [] current_id = item["ChildID"] while current_id: if current_id in path: return True # 发现环状结构 path.append(current_id) parent = next((x for x in data if x["ChildID"] == current_id), None) current_id = parent["ParentID"] if parent else None return False ``` --- ### **四、不同场景的适配方案** | 需求场景 | 实现方案 | 时间复杂度 | |------------------|-----------------------------------|-------------| | 小规模数据 | 递归遍历 | $O(n)$ | | 大规模数据 | 哈希表+层级映射 | $O(n)$ | | 需要完整路径显示 | 预处理 Path 字段 | $O(n \log n)$ | | 动态更新树节点 | 维护双向指针(parent/children) | $O(1)$ 更新 | --- ### **五、可视化调试方法** 生成缩进文本格式的树: ```python def print_tree(node, indent=0): print(' ' * indent + f'{node["id"]} ({node["name"]})') for child in node["children"]: print_tree(child, indent + 1) # 调用示例 root = build_tree(data) print_tree(root) ``` 输出结果: ``` A (Root) B (NodeA) D (NodeB) C (NodeA) ``` --- 通过以上方法,您可以将扁平数据转换为层次分明的树形结构。**关键点在于建立高效的父子关系映射**,并根据实际需求选择递归或迭代方案。如果数据量极大(超过10万条),建议使用非递归的层级遍历算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

blueSky-fan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值