2014-03-06 55 views
9

JavaScript的遞歸搜索我試圖返回一個JSON對象結構,看起來像這樣在JSON對象

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

所以這是一個樹狀父子關係的特定節點。每個節點都有一個唯一的ID。 我試圖找到一個特定的節點這樣

function findNode(id, currentNode) { 

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

我通過findNode("10", rootNode)執行例如搜索。但即使搜索找到匹配,函數始終會返回undefined。我有一種不好的感覺,即遞歸函數在找到匹配後不會停止,並且繼續運行一個finally返回undefined,因爲在後面的遞歸執行中它沒有達到返回點,但我不確定如何解決此問題。

請幫忙!

+1

因爲它是答案,我只想指出,foreach循環無法停止在JavaScript中。在算法中不要使用foreach。 – wayne

+0

爲什麼您首先在JSON對象上執行搜索?你也許應該考慮在JSON對象生成的地方進行搜索,希望是數據庫。 –

+0

@ jmb.mage因爲在現實世界中,你經常必須解決那些沒有理想環境,且細節遠不能實現的任務。這是其中之一。 – Dropout

回答

24

以遞歸方式搜索時,必須通過返回結果返回。不過,您不會返回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; 
    } 
} 
+1

謝謝!完美的作品。 – Dropout

+2

我不得不爲for循環添加一個額外的檢查(例如,for(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)); 

此方法將返回節點,如果它出現在節點列表。但是,這將循環遍歷節點的所有子節點,因爲我們無法成功打破流程。更好的實現將如下所示。

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

我用下面的

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

然後,你可以寫

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

現在這個工程對循環引用,你可以通過改變匹配字段,你的任何字段或組合樣功能matchCallback