JavaScript 数组结构与树结构的转换

语言: CN / TW / HK

theme: channing-cyan highlight: an-old-hope


前言

作为前端开发的同学,在与后端进行数据联调的时候,我们前端的同学处理Array数组结构的数据是最多的,listtablecard各种需要遍历的展示显示我们都会用数组来处理。当数组中涉及层级嵌套是我们的数组结构就需要进行Tree树结构的转化,常见的有目录树组件,区域选择组件等等。

这种树结构数据,前后端都可以处理,当有时候后端就是返回一个数组让前端处理的时候,我们就可以直接处理就行了。

Array结构 转 Tree结构

例如: 我们要把下面这种数组结构的转化为像tree那样嵌套的结构

js /** 数组结构数据 */ const arrayData = [ { id: 2, title: '中国', parent_id: 0 }, { id: 3, title: '广东省', parent_id: 2 }, { id: 4, title: '广州市', parent_id: 3 }, { id: 5, title: '天河区', parent_id: 4 }, { id: 6, title: '湖南省', parent_id: 2 }, { id: 1, title: '俄罗斯', parent_id: 0 } ]

使用递归的方法

  • 1、递归需分为两个函数来完成
  • 2、 以为返回的递归函数主要处理查找id添加children
  • 3、 由转化函数将结果返回 ```js /**
  • 递归查找添加children
  • @param {数组数据} data
  • @param {存放返回结果} result
  • @param {父id} pid */ function getChildren(data, result, pid) { for (const item of data) { if (item.parent_id === pid) { const newItem = { children: [], ...item } result.push(newItem) getChildren(data, newItem.children, item.id) } } }

/* * 转化方法 * @param {数组数据} data * @param {父id} pid * @returns / function arrayToTree(data, pid) { let result = [] getChildren(data, result, pid) return result }

console.log(arrayToTree(arrayData, 0)); ```

使用循环的方法

  • 1、使用数组的reduce方法将,data数组转为对象保存在对象变量obj中,每一项的id作为对象的key;
  • 2、遍历data数组,判断parent_id === 0的为第一层数组对象,pushresult数组,
  • 3、继续遍历,找爹现场,在 2中我们找到数组的第一层将作为其他层级的父层,
  • 例如: 我们在第一轮的时候 const parent = obj[item.parent_id] 这个parent对象对应的就是parent_id === 0title = 中国或者俄罗斯节点,依此类推在这个parent对象里不断添加children属性,直到他没有parent_id与自己id一样的children

js /** * 数组结构转为树结构 * @param {*} data 数组数据 * @returns */ function arrayToTree(data) { const result = [] const obj = data.reduce((pre, cur) => { pre[cur.id] = cur return pre }, {}) for (let item of data) { if (item.parent_id === 0) { result.push(item) continue } if (item.parent_id in obj) { const parent = obj[item.parent_id]; parent.children = parent.children || []; parent.children.push(item); } } return result } 转换后的结果图

image.png

Tree结构 转 Array结构

例如: 我们要把下面这种tree树结构的转化为扁平化的一维数组 js /** 树状形结构数据treeData */ const treeData = [ { id: 2, title: '中国', parent_id: 0, children: [ { id: 3, title: '广东省', parent_id: 2, children: [ { id: 4, title: '广州市', parent_id: 3, children: [ { id: 5, title: '天河区', parent_id: 4 } ] } ] }, { id: 6, title: '湖南省', parent_id: 2 } ] }, { id: 1, title: '俄罗斯', parent_id: 0, }, ]

使用递归的方法

  • 1、 使用数组的reduce方法, 解构数组的每一项,如果有children,就用concat 一层一层的抽取出来,使得每个对象项都包裹在一个[]下 ```js /**
  • 树结构数组扁平化
  • @param {*} data 树结构的数组
  • @returns */ function treeToArray(data) { return data.reduce((pre, cur) => { const { children = [], ...item } = cur;
    return pre.concat([{ ...item }], treeToArray(children)) }, []); } ```

reduce() 方法对数组中的每个元素按序执行一个由您提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。

数组的相关方法

使用循环的方法

image.png

Tree结构根据ID找路径

使用目录的时候会有这样的需求,根据id查找所在目录路径,也是递归实现。

  • 1、遍历树结构数组,判断id 是否为当前项的id,是就返回当前目录名词
  • 2、判断当前项是否有children依此递归。

js /** * 根据id查找所在目录路径 * @param {树结构的数组数据} tree * @param {要查找的id} id * @param {初始路径} path * @returns */ function parseTreePath(tree, id, path = "") { for (let i = 0; i < tree.length; i++) { let tempPath = path; // 避免出现在最前面的/ tempPath = `${tempPath ? tempPath + "/ " : tempPath}${tree[i].title}`; if (tree[i].id == id) return tempPath; else if (tree[i].children) { let reuslt = parseTreePath(tree[i].children, id, tempPath); if (reuslt) return reuslt; } } }; console.log(parseTreePath(treeData, 5));