web-dev-qa-db-ja.com

JSONオブジェクトでのJavaScript再帰検索

次のようなJSONオブジェクト構造で特定のノードを返そうとしています

_{
    "id":"0",
    "children":[
        {
            "id":"1",
            "children":[...]
        },
        {
            "id":"2",
            "children":[...]
        }
    ]
}
_

したがって、これはツリーのような子親関係です。すべてのnodeには一意のIDがあります。特定のnodeを見つけようとしています

_function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        currentNode.children.forEach(function (currentChild) {            
            findNode(id, currentChild);
        });
    }
}  
_

たとえばfindNode("10", rootNode)で検索を実行します。ただし、検索で一致が見つかった場合でも、関数は常にundefinedを返します。私は、一致を見つけた後、再帰関数が停止せず、最後にundefinedを実行し続けるという悪い感じがあります。なぜなら、後者の再帰実行では、戻り点に到達しないからです。これを修正する方法。

助けてください!

22
Dropout

再帰的に検索する場合、結果を返すことで結果を返さなければなりません。ただし、findNode(id, currentChild)の結果は返されません。

function findNode(id, currentNode) {
    var i,
        currentChild,
        result;

    if (id == currentNode.id) {
        return currentNode;
    } else {

        // Use a for loop instead of forEach to avoid nested functions
        // Otherwise "return" will not work properly
        for (i = 0; i < currentNode.children.length; i += 1) {
            currentChild = currentNode.children[i];

            // Search in the current child
            result = findNode(id, currentChild);

            // Return the result if the node has been found
            if (result !== false) {
                return result;
            }
        }

        // The node has not been found and we have no more options
        return false;
    }
}
38
Butt4cak3
function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        var result;
        currentNode.children.forEach(function(node){
            if(node.id == id){
                result = node;
                return;
            }
        });
        return (result ? result : "No Node Found");
    }
}
console.log(findNode("10", node));

このメソッドは、ノードリストにノードが存在する場合、そのノードを返します。ただし、forEachフローを正常に分割できないため、ノードのすべての子をループします。より良い実装は以下のようになります。

function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        for(var index in currentNode.children){
            var node = currentNode.children[index];
            if(node.id == id)
                return node;
            findNode(id, node);
        }
        return "No Node Present";
    }
}
console.log(findNode("1", node));
4
Triode

私は次を使用します

var searchObject = function (object, matchCallback, currentPath, result, searched) {
    currentPath = currentPath || '';
    result = result || [];
    searched = searched || [];
    if (searched.indexOf(object) !== -1 && object === Object(object)) {
        return;
    }
    searched.Push(object);
    if (matchCallback(object)) {
        result.Push({path: currentPath, value: object});
    }
    try {
        if (object === Object(object)) {
            for (var property in object) {
                if (property.indexOf("$") !== 0) {
                    //if (Object.prototype.hasOwnProperty.call(object, property)) {
                        searchObject(object[property], matchCallback, currentPath + "." + property, result, searched);
                    //}
                }
            }
        }
    }
    catch (e) {
        console.log(object);
        throw e;
    }
    return result;
}

その後、書くことができます

searchObject(rootNode, function (value) { return value != null && value != undefined && value.id == '10'; });

現在、これは循環参照で機能し、matchCallback関数を変更することにより、任意のフィールドまたはフィールドの組み合わせで一致させることができます。

3
Peter

私はツリー検索が本当に好きでした!ツリーは、今日の複雑な構造化タスクのほとんどにとって非常に一般的なデータ構造です。だから、昼食にも同じような仕事をしました。私もいくつかの深い研究をしましたが、実際には新しいものを発見していません!それで、今日私が得たものは、「現代のJS構文でどのように実装したか」です。

// helper
find_subid = (id, childArray) => {
    for( child of childArray ) {
        foundChild = find_id( i, child ); // not sub_id, but do a check (root/full search)!
        if( foundChild ) // 200 
            return foundChild;
    }
    return null; // 404
}

// actual search method
find_id = (id, parent) => (id == parent.id) : parent : find_subid(id, parent.childArray);
0
xakepp35