2014-03-06 15 views
9

Ich versuche, einen bestimmten Knoten in einem JSON-Objekt-Struktur zurückkehren, die wie folgtJavaScript rekursive Suche in JSON-Objekt

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

So sieht es eine baumartige Eltern-Kind-Beziehung. Jeder Knoten hat eine eindeutige ID. Ich versuche, einen bestimmten Knoten wie diese

function findNode(id, currentNode) { 

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

ich die Suche nach findNode("10", rootNode) zum Beispiel ausführen zu finden. Aber obwohl die Suche eine Übereinstimmung findet, gibt die Funktion immer undefined zurück. Ich habe das schlechte Gefühl, dass die rekursive Funktion nach dem Auffinden der Übereinstimmung nicht aufhört und weiter läuft und schließlich undefined zurückgibt, weil in den letzten rekursiven Ausführungen kein Rückkehrpunkt erreicht wird, aber ich bin mir nicht sicher, wie ich das beheben kann.

Bitte helfen!

+1

da es Antwort ist, möchte ich nur darauf hinweisen, dass foreach-Schleife nicht in Javascript stoppen kann. Verwenden Sie foreach nicht im Algorithmus. – wayne

+0

Warum führen Sie überhaupt eine Suche nach einem JSON-Objekt durch? Sie sollten vielleicht erwägen, die Suche an dem Ort durchzuführen, an dem das JSON-Objekt generiert wurde, hoffentlich die Datenbank. –

+0

@ jmb.mage, denn in der realen Welt müssen Sie oft Aufgaben lösen, die keine idealen Bedingungen haben und deren Details außerhalb Ihrer Reichweite liegen. Dies ist einer von ihnen. – Dropout

Antwort

24

Bei der rekursiven Suche müssen Sie das Ergebnis zurückgeben, indem Sie es zurückgeben. Sie geben das Ergebnis von findNode(id, currentChild) jedoch nicht 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; 
    } 
} 
+1

Danke! Funktioniert perfekt. – Dropout

+2

Ich musste der for-Schleife eine zusätzliche Überprüfung hinzufügen (dh für (i = 0; currentNode.children! == undefined && i

4
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)); 

Dieses Verfahren wird den Knoten zurück, wenn es in der Knotenliste vorhanden ist. Dies wird jedoch alle untergeordneten Elemente eines Knotens durchlaufen, da der forEach-Ablauf 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)); 
0

Ich verwende die folgende

var searchObject = function (object, matchCallback, currentPath, result, searched) { 
    currentPath = currentPath || ''; 
    result = result || []; 
    searched = searched || []; 
    if (searched.indexOf(object) !== -1) { 
     return; 
    } 
    searched.push(object); 
    if (matchCallback(object)) { 
     result.push({path: currentPath, value: object}); 
    } 
    for (var property in object) { 
     if (object.hasOwnProperty(property)) { 
      searchObject(object[property], matchCallback, currentPath + "." + property, result, searched); 
     } 
    } 
    return result; 
} 

Dann können Sie

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

schreiben Jetzt funktioniert dies auf zirkuläre Referenzen und Sie können durch eine Änderung auf ein beliebiges Feld oder Kombination von Feldern Sie passen wie die matchCallback Funktion.