多个属性的递归搜索

时间:2019-07-12 20:35:32

标签: javascript recursion

这是我拥有的一些JSON数据:

[
    {
        "name" : "X",
        "children" : [
            {
                "name" : "Y"
            },
            {
                "name" : "Z"
            }
        ]
    },
    {
        "name" : "A",
        "options" : [
            {
                "children" : [
                    {
                        "name" : "B"
                    },
                    {
                        "name" : "C"
                    }
                ]
            },
            {
                "children" : [
                    {
                        "name" : "D"
                    },
                    {
                        "name" : "E"
                    }
                ]
            }
        ],
        "children" : [
            {
                "name" : "F"
            },
            {
                "name" : "G"
            }
        ]
    }
]

我想检索与我要查找的名称匹配的对象。
我的问题是,由于有数据数组,

  • 如果在回溯调用中使用返回值并跳入第一个数组,它将在该数组的最后一项之后停止搜索。
  • 如果不将返回值放在递归调用上,则无法获取返回值。

获得匹配对象的最佳算法是什么:

{
    "name" : F
}

例如,如果我正在寻找 F

4 个答案:

答案 0 :(得分:1)

您可以检查上交的项目是否不是对象,然后返回undefined,如果找到所需名称,则返回该对象,否则从对象中迭代值并检查嵌套的对象。

方法:

  • 用于检查不是null的对象的模式,
  • Object.values用于获取对象的所有值,
  • Array#some,如果返回值为truthy(在这种情况下,找到一个对象),则允许短路,
  • 一个递归调用,它从深度嵌套调用中返回一个值。

function getObject(object, name) {
    var temp;
    if (!object || typeof object !== 'object') return;
    if (object.name === name) return object;            
    Object.values(object).some(o => temp = getObject(o, name));
    return temp;
}

var data = [{ name: 'X', children: [{ name: 'Y' }, { name: 'Z' }] }, { name: 'A', options: [{ children: [{ name: 'B' }, { name: 'C' }] }, { children: [{ name: 'D' }, { name: 'E' }] }], children: [{ name: 'F' }, { name: 'G' }] }];

console.log(getObject(data, 'F'));
console.log(getObject(data, 'A'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:0)

更新

下面是一个递归代码,应该测试传入的参数是一个数组(并检查每个元素)还是一个对象,并检查“ name”属性,如果不是我们想要的,则运行相同的递归每个属性的方法。这是代码:

retrieveObjectWithName(obj, name)
{
    // if incoming object has property name and it matches our search name
    if (obj.name === name) {
        return obj;
    }

    // if incoming object is an array then we iterate through it and test each element
    if (Array.isArray(obj)){
        for (var i = 0; i < obj.length; i++) {
            var result = retrieveObjectWithName(obj[i], name);
            if (result) {
                return result;
            }
        }
    }

    // if the incoming object is an object then we iterate through each property and test each property
    for (var property in obj) {
        if (object.hasOwnProperty(property)) {
            var result = retrieveObjectWithName(obj[property], name);
            if (result) {
                return result;
            }
        }
    }

    // nothing was found (at least on this level)
    return null;
}

答案 2 :(得分:0)

此代码可以永远嵌套。

const data = [{
    name: 'jamal 1',
    options: [{
        children: [{
            name: 'jamal 1 1 1',
        }, {
            name: 'jamal 1 1 2',
        }],
    }, {
        children: [{

            name: 'jamal 1 2 1',
        }, {
            name: 'jamal 1 2 2',
        }],
    }],
}, {
    name: 'jamal 2',
    children: [{
        name: 'jamal 2 1',

    }, {
        name: 'jamal 2 2',
    }],
}];

function compare(obj, comp) {
    for (const key in comp) {

        console.log(obj[key], comp[key]);
        if (obj.hasOwnProperty(key)) {
            if (obj[key] != comp[key]) {
                return false;
            }
        } else {
            return false;
        }
    }
    return true;
}

function search(object, query) {
    for (const item of object) {
        if (compare(item, query)) {
            return item;
        } else if (Array.isArray(item.options)) {
            const result = search(item.options, query);
            if (result) return result;
        } else if (Array.isArray(item.children)) {
            const result = search(item.children, query);
            if (result) return result;
        }
    }
    return null;
}


console.log(search(data, {name: 'jamal 1 1 2'})); // result {name: 'jamal 1 1 2'}

编辑

抱歉,该名称仅用于测试:)

答案 3 :(得分:0)

好吧,根据帖子,我无法避免存储返回值并检查它是否为null。我坚决做到这一点,但我发现这很脏而且没有优化。

function findField(fieldName, scope = fields){
    let i;
    let result;
    for(i=0; i < scope.length; i++){
        if(scope[i].name === fieldName){
            return scope[i];
        }
        else if ("options" in scope[i]){
            let j;
            for(j=0; j < scope[i].options.length; j++){
                result = findField(fieldName, scope[i].options[j].children)
                if(result) return result
            }
        }
        else {
            result = findField(fieldName, scope[i].children)
            if(result) return result
        }
    }
    return null
}

感谢您的帮助。