关于js 递归方法

题目描述

有2个数组

相关代码

var a = ['customer','supplier','materal','purchaseOrder','rolesMenge']
var b = [
    {
        name:'maindata',
        children:[
            {
                name:'customer',
                meta:{
                    title:'customer'    
                }
            },
            {
                name:'supplier',
                meta:{
                    title:'supplier'    
                }
            },
            {
                name:'materal',
                meta:{
                    title:'materal'    
                }
            },
        ]
    },
    {
        name:'purchase',
        children:[
            {
                name:'purchaseOrder',
                meta:{
                    title:'purchaseOrder'    
                }
            },
            {
                name:'purchaseGood',
                meta:{
                    title:'purchaseGood'    
                }
            },
        ]
    },
    {
        name:'stock',
        children:[
            {
                name:'stockOrder',
                meta:{
                    title:'stockOrder'    
                }
            }
        ]
    },
    {
        name:'config',
        children:[
            {
                name:'userConfig',
                children:[
                    {
                        name:'rolesMenge',
                        meta:{
                            title:'rolesMenge'    
                        }
                    }
                ]
            },
        ]
    }
]

我的代码

function getarr(a,b){
    return b.reduce((k,m) => {
        if(m.children){
            let obj = {
                name:m.name,
                children:[]
            }
            for(let j of m.children){
                if(j.children){
                    getarr(a,m.children)
                } else {
                    if(a.includes(j.meta.title)){
                        obj.children.push(j)
                    }
                }
                
            }
            if(obj.children.length){
                k.push(obj)
            }

        }
        return k
    },[])
}

你期待的结果是什么?实际看到的错误信息又是什么?

希望得到

[
    {
        name: "maindata",
        children:[
            {
                name:'customer',
                meta:{
                    title:'customer'    
                }
            },
            {
                name:'supplier',
                meta:{
                    title:'supplier'    
                }
            },
            {
                name:'materal',
                meta:{
                    title:'materal'    
                }
            }
         ]
     }, 
     {
        name:'purchase',
        children:[
            {
                name:'purchaseOrder',
                meta:{
                    title:'purchaseOrder'    
                }
            }
        ]
    },
    {
        name:'config',
        children:[
            {
                name:'userConfig',
                children:[
                    {
                        name:'rolesMenge',
                        meta:{
                            title:'rolesMenge'    
                        }
                    }
                ]
            },
        ]
    }
]
阅读 2.7k
1 个回答

前不久刚回答了另一个类似的问题,本来以为是一样的,仔细分析之后发现这两个问题有一点重大差异:

  • 这个问题要求结果保留原树结构,也就是说,符合条件节点的父路径上所有节点都要保留

新的 deal() 修改如下(含注释),顺便处理了之前那个问题结果中含大量空 children 的问题

/**
 * 递归过滤节点,但保留原树结构,即符合条件节点的父路径上所有节点不管是否符合条件都保留
 * @param {Node[]} nodes 要过滤的节点
 * @param {node => boolean} predicate 过滤条件,符合条件的节点保留
 * @return 过滤后的根节点数组
 */
function deal(nodes, predicate) {
    // 如果已经没有节点了,结束递归
    if (!(nodes && nodes.length)) {
        return;
    }

    const newChildren = [];
    for (const node of nodes) {
        if (predicate(node)) {
            // 如果自己(节点)符合条件,直接加入到新的节点集
            newChildren.push(node);
            // 并接着处理其 children
            node.children = deal(node.children, predicate);
        } else {
            // 如果自己不符合条件,需要根据子集来判断它是否将其加入新节点集
            // 根据递归调用 deal() 的返回值来判断
            const subs = deal(node.children, predicate);
            if (subs && subs.length) {
                // 1. 如果子孙集中有符合要求的节点(返回 [...]),加入
                node.children = subs;
                newChildren.push(node);
            }
            // 2. 否则,不加入(因为整个子集都没有符合条件的)
        }
    }
    return newChildren.length ? newChildren : void 0;
}

不过这不是最终答案,因为代码还可以进行优化。if 的两个分支中都需要递归,根据递归的结果来,结合对当前节点的检查来判断是否需要加入当前节点,所以循环内部可以修改一下

    for (const node of nodes) {
        const subs = deal(node.children, predicate);

        // 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中
        // 1. 子孙节点中存在符合条件的,即 subs 数组中有值
        // 2. 自己本身符合条件
        if ((subs && subs.length) || predicate(node)) {
            node.children = subs;
            newChildren.push(node);
        }
    }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题