web-dev-qa-db-de.com

Rekursive JavaScript-Suche in JSON-Objekten

Ich versuche, einen bestimmten Knoten in einer JSON-Objektstruktur zurückzugeben, der so aussieht

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

Es ist also eine baumähnliche Kind-Eltern-Beziehung. Jeder Knoten hat eine eindeutige ID ... Ich versuche, einen bestimmten Knoten so zu finden

function findNode(id, currentNode) {

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

Ich führe die Suche zum Beispiel mit findNode("10", rootNode) aus. Auch wenn die Suche eine Übereinstimmung findet, gibt die Funktion immer undefined zurück. Ich habe ein schlechtes Gefühl, dass die rekursive Funktion nach dem Finden des Matches nicht aufhört und weiterhin ausgeführt wird und schließlich undefined ausgeführt wird, da in letzteren rekursiven Ausführungen kein Rückkehrpunkt erreicht wird.

Bitte helfen 

17
Dropout

Wenn Sie rekursiv suchen, müssen Sie das Ergebnis zurückgeben, indem Sie es zurückgeben. Sie geben jedoch nicht das Ergebnis von findNode(id, currentChild) zurück.

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;
    }
}
33
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));

Diese Methode gibt den Knoten zurück, wenn er in der Knotenliste vorhanden ist. Dies durchläuft jedoch alle untergeordneten Knoten eines Knotens, da der forEach-Fluss nicht erfolgreich unterbrochen werden kann. Eine bessere Implementierung würde wie folgt aussehen.

function findNode(id, currentNode) {

    if (id == currentNode.id) {
        return currentNode;
    } else {
        var result;
        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

Ich benutze das Folgende

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;
}

Dann kannst du schreiben

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

Das funktioniert jetzt mit Zirkelverweisen und Sie können jedes Feld oder jede Kombination von Feldern anpassen, indem Sie die matchCallback-Funktion ändern.

1
Peter

Ich habe eine Baumsuche wirklich gemocht! Ein Baum ist eine äußerst verbreitete Datenstruktur für die meisten komplexen strukturierten Aufgaben von heute. Also hatte ich gerade eine ähnliche Aufgabe auch zum Mittagessen. Ich habe sogar gründlich recherchiert, aber nichts Neues gefunden! Was ich heute für Sie habe, ist "Wie habe ich das in moderne JS-Syntax implementiert":

// 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