当前位置:网站首页>js通过递归实现树形数据操作
js通过递归实现树形数据操作
2022-06-10 10:54:00 【SwJieJie】
一、处理复杂数据结构转成树形数据操作
案列一如下:
需求分析
1,根据fatherTreeCode判断是不是父级,为空是父级,然后处理成树形层级关系。
2,完成树形结构后再树形数据里面添加对应的key和value值进行显示。
原数据
const treeData = [
{
capList: [],
fatherTreeCode: "",
isLeaf: "0",
showSeqno: "1",
treeCode: "TRE0rv",
treeLevel: "1",
treeName: "根目录",
},
{
capList: [],
fatherTreeCode: "TRE0rv",
isLeaf: "0",
showSeqno: "4",
treeCode: "TRE0sw",
treeLevel: "2",
treeName: "物联网",
},
{
fatherTreeCode: "TRE0rv",
isLeaf: "1",
showSeqno: "4",
treeCode: "TRE0xw",
treeLevel: "2",
treeName: "云网业务",
capList: [
{
code: "del-vpn",
id: "8c15d2488ad24d55946e6ce0f5ea3f40",
name: "5G切片开通",
treeLevel: "12",
},
{
code: "netpe-resource-allocation-request",
id: "35202810e96442fda4d6aaa61122986b",
name: "5G资源预占",
treeLevel: "13",
},
],
},
];
代码如下:
function tree (data) {
const obj = {
}
for (const item of data) {
obj[item.treeCode] = item
}
const result = []
for (const item of data) {
if (obj[item.fatherTreeCode]) {
if (!obj[item.fatherTreeCode].capList) {
obj[item.fatherTreeCode].capList = []
}
obj[item.fatherTreeCode].capList.push(item)
} else {
result.push(item)
}
}
return result
}
let list = tree(treeData);
console.log(list, 'list');
function fn (data, index = '0-') {
return data.map((item, indexItem) => {
return {
value: `${
index}${
indexItem}`,
key: item.treeLevel,
treeName: item.treeName || item.name,
children: (() => {
if (item.capList && item.capList.length > 0) {
return fn(item.capList, `${
index}${
indexItem}-`);
} else {
return []
}
})()
}
})
}
console.log(fn(list));
处理后的数据
案列二如下:
需求分析:
据id和parentId把json数据结构转成树形状的数据结构
原数据
const temp = [
{
'id': 1,
'name': '1级1',
'parentId': 0
},
{
'id': 2,
'name': '2级1',
'parentId': 0
},
{
'id': 4,
'name': '1级1-1',
'parentId': 1
},
{
'id': 6,
'name': '1级1-1-1',
'parentId': 4
},
{
'id': 12,
'name': '2级1-1',
'parentId': 2
},
{
'id': 13,
'name': '3级1',
'parentId': 0
},
{
'id': 14,
'name': '3级1-1',
'parentId': 13
},
{
'id': 15,
'name': '1级1-1-1-1',
'parentId': 6
}
]
代码如下:
方法一:
const transData = (jsonArr, idStr, pidStr, childrenStr) => {
// 存放的最终结果树数组
const result = [];
const id = idStr;
const parentId = pidStr;
const children = childrenStr;
const len = jsonArr.length;
// 遍历得到以id为键名的对象(建立整棵树的索引)
const hash = {
};
jsonArr.forEach(item => {
hash[item[id]] = item;
});
for (let j = 0; j < len; j++) {
const jsonArrItem = jsonArr[j];
const hashItem = hash[jsonArrItem[parentId]];
if (hashItem) {
// 如果当前项还没有children属性,则添加该属性并设置为空数组
!hashItem[children] && (hashItem[children] = []);
hashItem[children].push(jsonArrItem);
} else {
result.push(jsonArrItem);
}
}
return result;
};
const jsonDataTree = transData(temp, 'id', 'parentId', 'children');
console.log(jsonDataTree)
方法二:
// 调用方法, temp为原始数据, result为树形结构数据
var result = generateOptions(temp)
// 开始递归方法
generateOptions(params) {
var result = []
for (const param of params) {
if (param.parentId === 0) {
// 判断是否为顶层节点
var parent = {
'id': param.id,
'label': param.name
}
parent.children = this.getchilds(param.id, params) // 获取子节点
result.push(parent)
}
}
return result
},
getchilds(id, array) {
const childs = []
for (const arr of array) {
// 循环获取子节点
if (arr.parentId === id) {
childs.push({
'id': arr.id,
'label': arr.name
})
}
}
for (const child of childs) {
// 获取子节点的子节点
const childscopy = this.getchilds(child.id, array)// 递归获取子节点
if (childscopy.length > 0) {
child.children = childscopy
}
}
return childs
}
递归生成后的树形结构数据
二、重新组合树结构中的数据
对原有的树形结构添加新的字段值
原数据
const treeData = [{
name: '2021资源',
key: '1',
isLeaf: false,
children: [{
name: '服务器',
isLeaf: false,
key: '6',
children: [
{
isLeaf: false,
name: '172.168.201.109',
key: '5',
children: [
{
isLeaf: true,
children: [],
name: 'ping丢包率',
key: '2',
}, {
isLeaf: true,
children: [],
name: 'ping状态',
key: '3',
},
],
},
{
isLeaf: true,
children: [],
name: '192.168.3.6',
key: '7',
},
],
}],
}];
// 重新组合树数据(根据需要来重组树结构中的属性字段)
const dealTreeData = (treeData) => {
const data = treeData.map((item) => ({
...item,
// 新增title字段
title: item.name,
// 如果children为空数组,则置为null
children: (item.children && item.children.length)
? dealTreeData(item.children)
: null,
}));
return data;
};
console.log(JSON.stringify(dealTreeData(treeData)));
结果:
// 打印结果
// [{
// name: '2021资源',
// key: '1',
// isLeaf: false,
// title: '2021资源',
// children: [{
// name: '服务器',
// isLeaf: false,
// key: '6',
// title: '服务器',
// children: [{
// isLeaf: false,
// name: '172.168.201.109',
// key: '5',
// title: '172.168.201.109',
// children: [{
// isLeaf: true,
// children: null,
// name: 'ping丢包率',
// key: '2',
// title: 'ping丢包率',
// }, {
// isLeaf: true,
// children: null,
// name: 'ping状态',
// key: '3',
// title: 'ping状态',
// }],
// }, {
// isLeaf: true,
// children: null,
// name: '192.168.3.6',
// key: '7',
// title: '192.168.3.6',
// }],
// }],
// }];
三、树形结构的基本操作使用
(1),获取树中的所有祖先节点名称
const treeData = [{
key: '全部',
title: '全部',
isLeaf: false,
children: [{
key: '数据库',
title: '数据库',
isLeaf: false,
children: [
{
key: 'mysql',
title: 'mysql',
isLeaf: false,
children: [
{
key: '137',
title: 'QPS',
isLeaf: true,
}, {
key: '146',
title: 'MySQL进程信息',
isLeaf: true,
},
],
},
{
key: 'oracle',
title: 'oracle',
isLeaf: false,
children: [
{
key: '137',
title: 'QPS',
isLeaf: true,
},
],
},
],
}],
}];
// 获取树的所有祖先节点名称
const getTreeParents = (data) => {
const parentKey = [];
data.forEach((item) => {
if (item.children && item.children.length) {
parentKey.push(item.key);
const temp = getTreeParents(item.children);
if (temp.length) {
parentKey.push(...temp);
}
}
});
return parentKey;
};
const parentKeys = getTreeParents(treeData);
console.log(parentKeys); // ["全部", "数据库", "mysql", "oracle"]
(2),获取树中叶子节点的总个数(节点中isLeaf为true的节点)
const treeData = {
name: '2021资源',
title: '2021资源',
key: '1',
isLeaf: false,
children: [{
name: '服务器',
isLeaf: false,
title: '服务器',
key: '6',
children: [
{
name: '172.168.201.109',
isLeaf: false,
title: '172.168.201.109',
key: '5',
children: [
{
name: 'ping丢包率',
isLeaf: true,
children: null,
title: 'ping丢包率',
key: '2',
}, {
name: 'ping状态',
isLeaf: true,
children: null,
title: 'ping状态',
key: '3',
},
],
},
{
name: '192.168.3.6',
isLeaf: true,
children: null,
title: '192.168.3.6',
key: '7',
},
],
}],
};
const getLeafNum = (treeNode) => {
let leafNum = 0;
if (!treeNode) {
return leafNum;
}
if (treeNode.children && treeNode.children.length) {
treeNode.children.forEach((item) => {
leafNum += getLeafNum(item);
});
} else {
if (treeNode.isLeaf) {
leafNum++;
}
}
return leafNum;
};
console.log(getLeafNum(treeData)); // 3
(3),根据过滤条件筛选出需要留下节点的树结构数据(般用于前端做树的查询功能。)
/** * 递归过滤节点,但保留原树结构,即符合条件节点的父路径上所有节点不管是否符合条件都保留 * @param {Node[]} nodes 要过滤的树 * @param {node => boolean} predicate 过滤条件,符合条件的节点保留(参数为函数,返回值为布尔值) * @param {node => boolean} wrapMatchFn 层级条件(参数为函数,返回值为布尔值) * @return 过滤后的包含根节点数组 */
export const filterSearchTree = (nodes, predicate, wrapMatchFn = () => false) => {
// 如果已经没有节点了,结束递归
if (!(nodes && nodes.length)) {
return []
}
const newChildren = []
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]
// 想要截止匹配的那一层(如果有匹配的则不用递归了,直接取下面所有的子节点)
if (wrapMatchFn(node) && predicate(node)) {
newChildren.push(node)
continue
}
const subs = filterSearchTree(node.children, predicate, wrapMatchFn)
// 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中
// 1. 子孙节点中存在符合条件的,即 subs 数组中有值
// 2. 自己本身符合条件
if ((subs && subs.length) || predicate(node)) {
node.children = subs || []
newChildren.push(node)
}
}
return newChildren.length ? newChildren : []
}
const treeData = [{
key: '全部',
title: '全部',
isLeaf: false,
children: [{
key: '数据库',
title: '数据库',
isLeaf: false,
children: [
{
key: 'mysql',
title: 'mysql',
isLeaf: false,
children: [
{
key: '142',
title: '慢查询',
isLeaf: true,
}, {
key: '137',
title: 'QPS',
isLeaf: true,
}, {
key: '143',
title: '用户列表',
isLeaf: true,
},
],
},
{
key: '166',
title: 'SQL',
isLeaf: true,
},
],
}],
}];
// 要查找的关键字
const searchValue = 'S';
// 筛选到的树结构数据
const newTreeData = filterSearchTree(
treeData,
(node) => {
if (node.title.indexOf(searchValue) !== -1) {
return true;
}
return false;
},
);
// const newTreeData = filterSearchTree(
// cloneTreeDatas,
// (node) => {
// if (node.title.includes(searchValue)) {
// return true
// }
// return false
// },
// (node) => {
// // 第二层(显示左侧角色组数据)
// if (node.groupName) {
// return true
// }
// return false
// }
// )
console.log(JSON.stringify(newTreeData));
// 打印的结果
// [{
// key: '全部',
// title: '全部',
// isLeaf: false,
// children: [{
// key: '数据库',
// title: '数据库',
// isLeaf: false,
// children: [{
// key: 'mysql',
// title: 'mysql',
// isLeaf: false,
// children: [{
// key: '137',
// title: 'QPS',
// isLeaf: true,
// children: null,
// }],
// }, {
// key: '166',
// title: 'SQL',
// isLeaf: true,
// children: null,
// }],
// }],
// }];
边栏推荐
- Carbon reduction in the construction industry is by no means a fresh idea experts suggest strengthening the transformation of rural buildings
- kubernetes 设置 Master 可调度与不可调度
- 隐式转换导致的cpu负载近100%
- PV操作每日一题-橘子苹果问题(初阶版)
- C 12 circular queue
- 使用ApiPost测试接口时需要先登录的接口怎么办(基于Cookie)?
- MIT6.824-lab2D-2022(日志压缩详细讲解)
- 更耐用的遊戲真無線耳機,電池超大續航持久,英雄G1上手
- Extending visual transformer to gigapixel images based on hierarchical self supervised learning
- Transfer of 30% equity of Zhuhai Gaoyuan Electric Energy Technology Co., Ltd., shared by tamigou
猜你喜欢

fcpx插件:PremiumVFX Animation Presets(动画循环预设) v1.0.1特别版

Vs code supports configuring remote synchronization

高考志愿填报,城市、学校与专业怎么选?

Working principle and application of single chip trigger or not gate

MySQL architecture

更耐用的游戏真无线耳机,电池超大续航持久,英雄G1上手

MIT6.824-lab2D-2022(日志压缩详细讲解)

解析:稳定币不是「稳定的币」 其本质是一种产品

Extending visual transformer to gigapixel images based on hierarchical self supervised learning

数商云通讯行业数字化供应链协同系统:赋能通讯企业改善供应业务,增强市场竞争力
随机推荐
【黄啊码】我用这个方式清理了谷歌浏览器的控制台
最近几篇较好论文实现代码(附源代码下载)
杰理之BLE 动态调节功率【篇】
PV operation daily question - orange apple question (advanced version)
二进制、八进制、十进制、十六进制间互转(整数加小数)
What about the interface that needs to be logged in first when using the apipost test interface (based on cookies)?
在线文档协作工具,是提高工作效率的第一步
C 12 circular queue
杰理之BLE timer 时钟源不能选 OSC 晶振【篇】
建筑业减碳绝非一招鲜 专家建议加强改造农村建筑
Modstartcms enterprise content site building system (supporting laravel9) v4.1.0
Can I open an account for online stock trading? Is it safe?
单片机触发器或非门工作原理以及用途
对接上百个第三方 API 后的思考与沉淀
golang CLI框架--cobra
Common shell commands - 02 compression and decompression
PV operation daily question - orange apple question (Preliminary Edition)
VS Code支持配置远程同步了
[untitled]
How to choose cities, schools and majors for the college entrance examination?