JavaScript 递归查找节点返回 null

JavaScript recursion find node return null

提问人:Doe 提问时间:12/19/2017 最后编辑:CœurDoe 更新时间:12/1/2018 访问量:270

问:

如何获取匹配节点? 尽管显示匹配节点的警报,但我总是得到 null 返回。

必须有一个递归的保证。

我只想为ID找到相应的节点元素。 这甚至可以通过jQuery为JSON对象提供吗?

function getNode(processingNode, searchNodeId) {
  if(processingNode.tags == searchNodeId) {
    alert("match!");
    return processingNode;
  }
  else {
    var result = null;
    
    for(var i = 0; i < processingNode.nodes.length; i++) {
      result = getNode(processingNode.nodes[i], searchNodeId);
    }
    
    return result;
  }
}

var nodes = [{
  "tags": "1",
  "text": "BG",
  "nodes": [{
    "tags": "11",
    "text": "DLT",
    "nodes": []
  }, {
    "tags": "12",
    "text": "HBM",
    "nodes": []
  }, {
    "tags": "13",
    "text": "MBM",
    "nodes": []
  }, {
    "tags": "14",
    "text": "RT",
    "nodes": [{
      "tags": "141",
      "text": "FSP",
      "nodes": []
    }, {
      "tags": "142",
      "text": "HHR",
      "nodes": []
    }, {
      "tags": "143",
      "text": "KHR",
      "nodes": []
    }, {
      "tags": "144",
      "text": "KM",
      "nodes": []
    }, {
      "tags": "145",
      "text": "Sauger",
      "nodes": []
    }, {
      "tags": "146",
      "text": "SM",
      "nodes": []
    }]
  }, {
    "tags": "2",
    "text": "ST",
    "nodes": []
  }, {
    "tags": "3",
    "text": "WHT",
    "nodes": []
  }, {
    "tags": "4",
    "text": "ZDLT",
    "nodes": []
  }, {
    "tags": "5",
    "text": "ZHBM",
    "nodes": []
  }, {
    "tags": "6",
    "text": "ZMM",
    "nodes": []
  }, {
    "tags": "7",
    "text": "ZRT",
    "nodes": []
  }, {
    "tags": "8",
    "text": "ZST",
    "nodes": []
  }, {
    "tags": "9",
    "text": "ZHT",
    "nodes": []
  }]}
]

$(function() {
  var matchingNode = getNode(nodes[0], 142);
  alert(matchingNode);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

JavaScript 递归 null

评论

0赞 zfrisch 12/19/2017
只是一个提示:明智的做法是不要在注释/数据结构中使用常见属性的名称。例如,您在问题中交替使用术语 ID 和标签。 并且已经频繁使用,在 Node 对象上分配了属性。当其他人试图理解你的代码时,它可能而且绝对会导致混乱。idtagName
0赞 Mulan 12/19/2017
我知道你可能对这一切很陌生,所以我要指出,你所犯的一些错误只是因为命令式风格存在陷阱而发生的。请查看我的答案,看看如何避免痛苦的 for 循环、变量(重新)赋值和单分支 if 语句。

答:

0赞 ibrahim mahrir 12/19/2017 #1

解释:

即使在找到匹配项后,您的循环也会继续循环,因此,如果其他元素(匹配元素之后的元素)与给定的 ID 不匹配,则该元素将被覆盖。forresultnull

例如,如果在第 5次迭代中我们得到了一个结果,那么我们应该停止循环并返回。相反,您的代码会继续查找,因此,如果最后一次迭代不匹配,将被分配值(在第 5迭代时覆盖前一个值)。结论:只有当数组的最后一项与 ID 匹配时,您的代码才有效(在这种情况下,循环无论如何都会停止)。resultnull

建议的修复方法:

将循环更改为如下所示:

var result = null;
for(var i = 0; i < processingNode.nodes.length; i++) {
    result = getNode(processingNode.nodes[i], searchNodeId);
    if(result) {            // if we got a result
         return result;     // then return immediately and stop looping
    }
}
return result;              // keep this in case we don't find anything (or remove it as undefined will be returned implicitly), or change to simply 'return null;'

工作实例:

function getNode(processingNode, searchNodeId) {
  if(processingNode.tags == searchNodeId) {
    alert("match!");
    return processingNode;
  }
  else {
    var result = null;
    
    for(var i = 0; i < processingNode.nodes.length; i++) {
      result = getNode(processingNode.nodes[i], searchNodeId);
      if(result) return result;
    }
    
    return result;
  }
}

var nodes = [{
  "tags": "1",
  "text": "BG",
  "nodes": [{
    "tags": "11",
    "text": "DLT",
    "nodes": []
  }, {
    "tags": "12",
    "text": "HBM",
    "nodes": []
  }, {
    "tags": "13",
    "text": "MBM",
    "nodes": []
  }, {
    "tags": "14",
    "text": "RT",
    "nodes": [{
      "tags": "141",
      "text": "FSP",
      "nodes": []
    }, {
      "tags": "142",
      "text": "HHR",
      "nodes": []
    }, {
      "tags": "143",
      "text": "KHR",
      "nodes": []
    }, {
      "tags": "144",
      "text": "KM",
      "nodes": []
    }, {
      "tags": "145",
      "text": "Sauger",
      "nodes": []
    }, {
      "tags": "146",
      "text": "SM",
      "nodes": []
    }]
  }, {
    "tags": "2",
    "text": "ST",
    "nodes": []
  }, {
    "tags": "3",
    "text": "WHT",
    "nodes": []
  }, {
    "tags": "4",
    "text": "ZDLT",
    "nodes": []
  }, {
    "tags": "5",
    "text": "ZHBM",
    "nodes": []
  }, {
    "tags": "6",
    "text": "ZMM",
    "nodes": []
  }, {
    "tags": "7",
    "text": "ZRT",
    "nodes": []
  }, {
    "tags": "8",
    "text": "ZST",
    "nodes": []
  }, {
    "tags": "9",
    "text": "ZHT",
    "nodes": []
  }]}
]

$(function() {
  var matchingNode = getNode(nodes[0], 142);
  alert(matchingNode);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

0赞 Mulan 12/19/2017 #2

正方形 1

首先,没有“JSON 对象”这样的东西——JSON 始终是一个字符串。程序中有一个 JavaScript 对象。像这样手动写出每个节点的数据,使用 JavaScript 对象文字语法有点粗糙,因此我们将从为节点创建一个构造函数开始

// Node :: (String, String, [Node]) -> Node
const Node = (tags, text, nodes = []) =>
  ({ tags, text, nodes })

现在我们这样写数据

const tree = 
  Node ("1", "BG",
   [ Node ("11", "DLT")
   , Node ("12", "HBM")
   , Node ("13", "MBM")
   // ...
   ] )

在树中搜索特定节点是一项基本操作,但将我们的搜索限制在特定字段(即)是一个任意限制——让我们使我们的搜索函数通用,以便我们可以搜索我们想要的任何内容tags

// searchTree :: ((Node -> Boolean), Node, Int) -> Node?
const searchTree = (f, node, cursor = 0) =>
  cursor === node.nodes.length
    ? f (node)
      ? node
      : null
    : searchTree (f, node.nodes [cursor]) || searchTree (f, node, cursor + 1)

有了通用搜索功能,我们可以轻松实现按标签搜索功能

// getNodeByTags :: (Node, String) -> Node?
const getNodeByTags = (node, tags) =>
  searchTree (n => n.tags === tags, node)

这是一个完整的演示,展示了它的全部工作 - 最后一行演示了实现选择的多功能性

const Node = (tags, text, nodes = []) =>
  ({ tags, text, nodes })
  
const searchTree = (f, node, cursor = 0) =>
  cursor === node.nodes.length
    ? f (node)
      ? node
      : null
    : searchTree (f, node.nodes [cursor]) || searchTree (f, node, cursor + 1)

const getNodeByTags = (node, tags) =>
  searchTree (node => node.tags === tags, node)

const tree =
  Node ("0", "ROOT",
    [ Node ("1", "BG",
      [ Node ("11", "DLT")
      , Node ("12", "HBM")
      , Node ("13", "MBM")
      , Node ("14", "RT",
        [ Node ("141", "FSP")
        , Node ("142", "HHR")
        , Node ("143", "KHR")
        , Node ("144", "KM")
        , Node ("145", "Sauger")
        , Node ("146", "Sm")
        ] )
      ] )
    , Node ("2", "ST")
    , Node ("3", "WHT")
    , Node ("4", "ZDLT")
    , Node ("5", "ZHBM")
    , Node ("6", "ZMM")
    ] )

console.log (getNodeByTags (tree, "142"))
// { tags: '142', text: 'HHR', nodes: [] }

console.log (getNodeByTags (tree, "999"))
// null

console.log (searchTree (n => n.text === "ZDLT", tree))
// { tags: '4', text: 'ZDLT', nodes: [] }

接下来要读什么:深度优先搜索