讲扁平化的数组数据转为树形结构

核心调用自己

复制代码
export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => {//校验是不是数组
  if (!Array.isArray(data)) {
   console.warn('data must be an array')
   return []
  }

  //配置对象,有则用,无则默认

  const config = {
    id: id || 'id',
    parentId: parentId || 'parentId',
    childrenList: children || 'children'
  }
复制代码

 

  • data: 输入的数据源,必须是一个数组。
  • id: 节点的唯一标识字段,默认为 'id'
  • parentId: 父节点的标识字段,默认为 'parentId'
  • children: 孩子节点的字段名,默认为 'children'

定义数组/对象辅助

const childrenListMap = {}
const nodeIds = {}
const tree: any[] = []
//childrenListMap: 用于存储每个父节点对应的孩子节点列表。
//nodeIds: 用于存储每个节点的引用,以便快速查找。
//tree: 用于存储最终的树形结构。

构建映射关系

复制代码
for (const d of data) {
  const parentId = d[config.parentId]
  if (childrenListMap[parentId] == null) {
    childrenListMap[parentId] = []
  }
  nodeIds[d[config.id]] = d
  childrenListMap[parentId].push(d)
}
//遍历数据数组 data,对于每个节点 d:
//获取其父节点的 ID parentId。
//如果 childrenListMap 中没有 parentId 对应的数组,则创建一个空数组。
//将节点 d 存储在 nodeIds 中,以便后续查找。
//将节点 d 添加到 childrenListMap[parentId] 中。
复制代码

找根节点

复制代码
for (const d of data) {
  const parentId = d[config.parentId]
  if (nodeIds[parentId] == null) {
    tree.push(d)
  }
}
//再次遍历数据数组 data,对于每个节点 d:
//获取其父节点的 ID parentId。
//如果 nodeIds 中没有 parentId 对应的节点,则说明该节点是根节点,将其添加到 tree 中。
复制代码

递归构建子节点

复制代码
for (const t of tree) {
  adaptToChildrenList(t)
}

function adaptToChildrenList(o) {
  if (childrenListMap[o[config.id]] !== null) {
    o[config.childrenList] = childrenListMap[o[config.id]]
  }
  if (o[config.childrenList]) {
    for (const c of o[config.childrenList]) {
      adaptToChildrenList(c)
    }
  }
}
//重点:adaptToChildrenList
复制代码
  • 遍历 tree 中的每个根节点 t,调用 adaptToChildrenList 函数。
  • adaptToChildrenList 函数的作用是递归地为每个节点添加其孩子节点:
    • 如果 childrenListMap 中存在当前节点 o 的孩子节点列表,则将其赋值给 o[config.childrenList]
    • 如果 o[config.childrenList] 存在,则递归调用 adaptToChildrenList 处理每个孩子节点 c

完整代码

复制代码
/**
 * 构造树型结构数据
 * @param {*} data 数据源
 * @param {*} id id字段 默认 'id'
 * @param {*} parentId 父节点字段 默认 'parentId'
 * @param {*} children 孩子节点字段 默认 'children'
 */
export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => {
  if (!Array.isArray(data)) {
    console.warn('data must be an array')
    return []
  }
  const config = {
    id: id || 'id',
    parentId: parentId || 'parentId',
    childrenList: children || 'children'
  }

  const childrenListMap = {}
  const nodeIds = {}
  const tree: any[] = []

  for (const d of data) {
    const parentId = d[config.parentId]
    if (childrenListMap[parentId] == null) {
      childrenListMap[parentId] = []
    }
    nodeIds[d[config.id]] = d
    childrenListMap[parentId].push(d)
  }

  for (const d of data) {
    const parentId = d[config.parentId]
    if (nodeIds[parentId] == null) {
      tree.push(d)
    }
  }

  for (const t of tree) {
    adaptToChildrenList(t)
  }

  function adaptToChildrenList(o) {
    if (childrenListMap[o[config.id]] !== null) {
      o[config.childrenList] = childrenListMap[o[config.id]]
    }
    if (o[config.childrenList]) {
      for (const c of o[config.childrenList]) {
        adaptToChildrenList(c)
      }
    }
  }

  return tree
}
复制代码

这个函数通过构建父节点到孩子节点的映射关系,并找到根节点,然后递归地为每个节点添加其孩子节点,最终将扁平化的数据数组转换为树形结构的数据。

posted @   给第一张敬个礼  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示