递归在工作中常见的业务场景

1,282 阅读3分钟

递归看似平常工作中很少用。实际上在一些特定业务场景中,用到的还蛮多。

场景一:对于多层嵌套数据结构,现在如何递归查找,直到找到id为某个具体指的对象?

这个常用在树形菜单中,当然一般我们会基于第三方组件库开发,第三方组件库提供了对应的事件可以得到当前的勾选项,如果需要我们自己手写。那递归就派上了用场:


实现一:
 
function digui(data, id) {
 
        let value = null;
 
        for (const item of data) {
 
          if (item.id === id) {
 
            value = item;
 
            break;
 
          }
 
          if (item.children) {
 
            const _value = digui(item.children, id);
 
            if (_value) {
 
              return _value;
 
            }
 
          }
 
        }
 
        return value;
 
    } 
 
  console.log(digui(arr,999));

方法二:
 
let result = null

function handleDFS (arr, tid) {
 
  let i = 0;
 
  while (arr[i]) {
 
    if (arr[i].id === tid) {
 
        result = arr[i]
 
        return
 
    }
 
    if (arr[i].children) handleDFS(arr[i].children, tid)
 
    i++
 
  }
 
  return result
 
}

场景二:根据登录用户的权限code,动态过滤获取最后的树形菜单数据

这个场景非常普遍。用到递归可以事半功倍:

下面这个例子1.

let arr=["a","b","c","d","e"] //假设是后端给的权限code

let menu=[ //menu数组我们自己配置的菜单,menu中的children可能无限极//一级数据无code,但是children有code,保留有code并且code为arr里的选项        {            name:"项目一",            children:[                {name:"项目一(1)",code:"a" },                {name:"项目一(2)",code:"b" },                {name:"项目一(3)",code:"kkk" },            ]
        },
        {
            
            name:"项目二",
            children:[
                {name:"项目一(1)",code:"yyy" },
                {name:"项目一(2)",code:"d" },
                {name:"项目一(3)",code:"" },
            ]
        },
        {
             //一级数据有code,保留
            name:"项目三",
            code:"c"
        },
        {
            name:"项目四",
            code:"d"
        },
         //一级数据无code,剔除
        {
            name:"项目五",
        },
    ]

最后要得到的结果如图:把所有满足要求的项平铺,如何实现?

let res=[
 {name'项目一(1)'code'a'}
 {name'项目一(2)'code'b'}
 {name'项目一(2)'code'd'}
 {name'项目三'code'c'}
 {name'项目四'code'd'}
]

解法:


let processUnit=(item)=>{
    const {code}=item;
    let result=null;
    if(arr.includes(code)){
        result=item
    }
    return result
}
 
let getMenu=(menu)=>{
 
    let res=[];
    menu.forEach(item=>{
       const {children}=item;
       if(Array.isArray(children)){
 
            let data=getMenu(children);
            res=[...res,...data]
       }else{
           let result=processUnit(item);
           result&&(res.push(result))
       }
    })
    return res
}
console.log("结果是:",getMenu(menu))

针对上面例子,实际场景中可能还会是另一种需求: 过滤出menu数组中含有code并且code存在于权限列表中的数据。比如

{ name:"项目一",
    children:[ 
        {name:"项目一(1)",code:"a" },
        {name:"项目一(2)",code:"b" },
        {name:"项目一(3)",code:"kkk" }, 
    ]
},
该项本身没有code,但是其子项“项目1”“项目2”的code都在权限列表中,所以该项应该被保留,同事剔除code伟"kkk"的第三项,这项本身过滤后应该变成这样:
{ name:"项目一",
    children:[ 
        {name:"项目一(1)",code:"a" },
        {name:"项目一(2)",code:"b" },
    ]
},
其他项同理:
也就是menu数组最后的结果应该是:
{
            //一级数据无code,但是children有code,保留有code并且code为arr里的选项
            name:"项目一",
            children:[
                {name:"项目一(1)",code:"a" },
                {name:"项目一(2)",code:"b" },
                
            ]
        },
        {
            
            name:"项目二",
            children:[
              
                {name:"项目一(2)",code:"d" },
   
            ]
        },
        {

            name:"项目三",
            code:"c"
        },
        {
            name:"项目四",
            code:"d"
        },

}

解法:


let getMenu=(menu)=>{
 
    let res=[];
    menu.forEach(item=>{
       const {children}=item;
       if(Array.isArray(children)){
 
        let temp={...item,children:item.children.filter(k=>arr.includes(k.code))} 
        res=[...res,temp]
       }else{
           let result=processUnit(item);
           result&&(res.push(result))
       }
    })
    return res
}
 
let processUnit=(item)=>{
    const {code}=item;
    let result=null;
    if(arr.includes(code)){
        result=item
    }
    return result
}

let res=getMenu(menu)
console.log(res)

场景三:数据扁平:如果有子项,则抽出来平铺。最后返回一个平铺的数组

let arr=[
    {
        catalogCode: "0"
        catalogName: "首页"
        refImgNum: 131
    },
    {
        catalogCode: "001"
        catalogName: "卧室",
        childCatalogs:
            [
                catalogCode: "015"
                catalogName: "主卧"
                refImgNum: 0
            ]
    },
    {
        catalogCode: "014"
        catalogName: "餐厅"
        refImgNum: 1
    }
 
]
 
//最后的结果为
arr=[
 
 {
        catalogCode: "0"
        catalogName: "首页"
        refImgNum: 131
    },
    {
        catalogCode: "001"
        catalogName: "卧室",
      
    },
    {
         catalogCode: "015"
         catalogName: "主卧"
         refImgNum: 0
    },
    {
        catalogCode: "014"
        catalogName: "餐厅"
        refImgNum: 1
    }
]
解法:
const flatArr=(ary)=>{
	let result = [];
	
	for(let i = 0; i < ary.length; i++){
		let item = ary[i];
		result.push(item);
		if (item.childCatalogs){
			result.push(...flatArr(item.childCatalogs));		
		} 
	}
	return result
}
 
export {flatArr}