js 常见递归方式

js 常见递归方式js 常见递归方式 js 递归

大家好,欢迎来到IT知识分享网。

js 平铺

js 数组平铺

  1. 递归法
var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]]; function fn(arr){ let arr1 = [] arr.forEach((val)=>{ if(val instanceof Array){ console.log(1) arr1 = arr1.concat(fn(val)) }else{ arr1.push(val) } }) return arr1 } fn(arr) 
  1. reduce
 function fn(arr) { return arr.reduce((prev, cur) => { return prev.concat(Array.isArray(cur) ? fn(cur) : cur) }, []) } 
  1. ES6 flat(Infinity)
let arr2 = arr.flat(Infinity) 

js 数组对象平铺

const json = [ { id: 1, title: "课程1", children: [ { id: 4, title: "课程1-1" }, { id: 5, title: "课程1-2", children: [ { id: 6, title: "课程1-2-1" }, { id: 7, title: "课程1-2-2" }, ], }, ], }, { id: 2, title: "课程2" }, { id: 3, title: "课程3" }, ]; let arr = []; function fn(j) { j.forEach(item => { arr.push(item) //循环判断是否有children if (item.children) { //如果有 递归去除 fn(item.children) } }) // console.log(1) console.log('arr',JSON.stringify(arr)) // debugger arr.forEach(item => { // 删除children delete item.children }) // } fn(json) 

js 数组对象平铺

 const flatData = (data) => { return data.reduce((prev, curr) => { prev.push(curr); if (curr.children &&curr.children.length > 0) { prev.push(...flatData(curr.children)); // 删除children delete curr.children } return prev; }, []); }; } // 把树结构数据打平为一维数组 const flatTree = (treeData) => { let result = [] treeData.forEach((item) => { // 先克隆一份数据作为第一层级的填充 let res = JSON.parse(JSON.stringify(item)) delete res.children result.push(res) if (item.children && item.children.length > 0) { // 如果当前children为数组并且长度大于0,才可进入flatTree()方法 result = result.concat(flatTree(item.children)) } }) return result } 

js 递归

简单示例

//必须要有if判断进行出栈,不然会进行死循环 <script> function factorial(n) { if (n == 1) return n; return n * factorial(n - 1) } console.log(factorial(5)) // 5 * 4 * 3 * 2 * 1 = 120 </script> 

js树结构数据的递归

export const getTreeData = (nodes, nodeId,propertiesInp)=>{ for(var i=0;i<nodes.length;i++){ let node = nodes[i] let {children} = node if(node.nodeId === nodeId){ node.input = { ...node.input, ...{ properties: {...propertiesInp} } } } if(children && children.length> 0){ getTreeData(children, nodeId, propertiesInp) } } } 

js找上级节点

数据结构

 let data = [ { "id": 1, "label": "猫爷爷", "children": [ { "id": 2, "label": "猫爸1", "children": [ { "id": 3, "label": "猫崽1-1", }, { "id": 4, "label": "猫崽1-2", } ], }, { "id": 5, "label": "猫爸2", "children": [ { "id": 6, //根据这个id,查找它的所有上级 "label": "猫崽2-1", }, { "id": 7, "label": "猫崽2-2", }, ], }, ] }, { "id": 7, "label": "猪爷爷", "children": [ { "id": 8, "label": "猪爸1", "children": [ { "id": 9, "label": "猪崽1", }, { "id": 10, "label": "猪崽2", } ], }, ] }, ] 

JS树形结构,通过子节点,查找上级所有父节点

 let target = { "id": 6, "label": "猫崽2-1" } let result = [] this.findParent(data, target, result) console.log(result) // 打印出结果:['猫爷爷', '猫爸2', '猫崽2-1'] //data:要遍历的数据, target:查找目标, result用于装查找结果的数组 findParent(data, target, result) { for (let i in data) { let item = data[i] if (item.id === target.id) { //将查找到的目标数据加入结果数组中 //可根据需求unshift(item.id)或unshift(item) result.unshift(item.label) return true } if (item.children && item.children.length > 0) { let ok = this.findParent(item.children, target, result) if (ok) { result.unshift(item.label) return true } } } //走到这说明没找到目标 return false } 

获取树中的所有祖先节点名称

/ * 获取树的所有祖先节点指定的key名 * @param {Array} treeData 树数据 * @param {String} childrenStr 子节点的键名 * @param {String} keyStr 获取指定的key名 * @returns 获取树链路上所有指定的key名数组 */ const getTreeParents= (treeData, childrenStr = 'children', keyStr = 'label') => { const parentKey = [] treeData.forEach((item) => { if (item[childrenStr] && item[childrenStr].length) { parentKey.push(item[keyStr]) const temp = getTreeParents(item[childrenStr], childrenStr, keyStr) if (temp.length) { parentKey.push(...temp) } } }) return parentKey } const parentKeys = getTreeParents(data); 

扩展

据id和pid把json结构 转 树状结构

const jsonData = [ { id: '0', pid: '-1', name: '666' }, { id: '4', pid: '1', name: '大家电' }, { id: '5', pid: '1', name: '生活电器' }, { id: '1', pid: '0', name: '家用电器' }, { id: '2', pid: '0', name: '服饰' }, { id: '3', pid: '0', name: '化妆' }, { id: '7', pid: '4', name: '空调' }, { id: '8', pid: '4', name: '冰箱' }, { id: '9', pid: '4', name: '洗衣机' }, { id: '10', pid: '4', name: '热水器' }, { id: '11', pid: '3', name: '面部护理' }, { id: '12', pid: '3', name: '口腔护理' }, { id: '13', pid: '2', name: '男装' }, { id: '14', pid: '2', name: '女装' }, { id: '15', pid: '7', name: '海尔空调' }, { id: '16', pid: '7', name: '美的空调' }, { id: '19', pid: '5', name: '加湿器' }, { id: '20', pid: '5', name: '电熨斗' }, { id: '21', pid: '20', name: '电熨斗子项' }, ]; / * 根据id和pid把json结构 转 树状结构 * @param jsonArr {json} json数据 * @param idStr {String} id的属性名 * @param pidStr {String} 父id的属性名 * @param childrenStr {String} children的属性名 * @return {Array} 数组 */ const transData = (jsonArr, idStr, pidStr, childrenStr) => { // 存放的最终结果树数组 const result = []; const id = idStr; const pid = 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[pid]]; if (hashItem) { // 如果当前项还没有children属性,则添加该属性并设置为空数组 !hashItem[children] && (hashItem[children] = []); hashItem[children].push(jsonArrItem); } else { result.push(jsonArrItem); } } return result; }; const jsonDataTree = transData(jsonData, 'id', 'pid', 'children'); console.log(jsonDataTree); 

重新组合树结构中的数据 : 一般用于因后端给的数据字段不够完善,类型不正确,需要前端进行处理树数据。

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', // }], // }], // }]; 

获取树中叶子节点的总个数(节点中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 

根据过滤条件筛选出需要留下节点的树结构数据: 一般用于前端做树的查询功能。

/ * 递归过滤节点,但保留原树结构,即符合条件节点的父路径上所有节点不管是否符合条件都保留 * @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, // }], // }], // }]; 

参考链接 : https://blog.csdn.net/helloxiaoliang/article/details/

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/118523.html

(0)
上一篇 2025-11-12 16:20
下一篇 2025-11-12 16:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信