讲扁平化的数组数据转为树形结构
核心调用自己
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 }
这个函数通过构建父节点到孩子节点的映射关系,并找到根节点,然后递归地为每个节点添加其孩子节点,最终将扁平化的数据数组转换为树形结构的数据。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通