【问题标题】:How to stop this recursive function?如何停止这个递归函数?
【发布时间】:2016-04-16 15:58:16
【问题描述】:

我有 javascript 数组,其中每个项目都有对父项的引用,并且它们可以循环(循环引用)。示例:

[
        {"id": 1, "firstName": "Macko","parentId": 12},
        {"id": 2, "firstName": "Jess","parentId": 1},
        {"id": 3, "firstName": "Peter","parentId": 1},
        {"id": 4, "firstName": "Lisa", "parentId": 1},
        {"id": 5, "firstName": "Megan","parentId": 1},
        {"id": 6, "firstName": "John", "parentId": 4},
        {"id": 7, "firstName": "Joe", "parentId": 4},
        {"id": 8, "firstName": "Matthew","parentId": 2},
        {"id": 9, "firstName": "Peter","parentId": 2},
        {"id": 10, "firstName": "Dio","parentId": 5},
        {"id": 11, "firstName": "Hello","parentId": 5},
        {"id": 12, "firstName": "Ana", "parentId": 4}
]

我需要根据所选记录创建嵌套数据结构以将其显示在 DOM 中,这是我通过如下递归函数实现的(来源 here

function getNestedChildren(arr, parent) {
  var out = []
  for(var i in arr) {
    if(arr[i].parent == parent) {
        var children = getNestedChildren(arr, arr[i].id)

        if(children.length) {
            arr[i].children = children
        }
        out.push(arr[i])
    }
  }
  return out
}

它确实很好用,但不适用于循环数据结构。问题是我需要在函数到达它开始的元素之前停止函数执行。

我怎样才能做到这一点?

【问题讨论】:

  • 添加一个参数(例如数组)来保存已访问 ID 的列表,以便您可以检查它并在适当时停止。
  • @Cyb3rFly3r 我试过了,但结果很奇怪或不完整。你能发布一个例子吗?我可能把条件放在错误的地方。
  • 不清楚你的预期结果是什么,因为原始代码总是产生一个空数组。

标签: javascript arrays circular-reference


【解决方案1】:

checked 数组保存所有对象(父对象)getNestedChildrenids 已被调用。

如果当前子级的id 在该数组中,则不要将其作为子级包含。

var arr = [
  {"id": 1, "firstName": "Macko","parentId": 12},
  {"id": 2, "firstName": "Jess","parentId": 1},
  {"id": 3, "firstName": "Peter","parentId": 1},
  {"id": 4, "firstName": "Lisa", "parentId": 1},
  {"id": 5, "firstName": "Megan","parentId": 1},
  {"id": 6, "firstName": "John", "parentId": 4},
  {"id": 7, "firstName": "Joe", "parentId": 4},
  {"id": 8, "firstName": "Matthew","parentId": 2},
  {"id": 9, "firstName": "Peter","parentId": 2},
  {"id": 10, "firstName": "Dio","parentId": 5},
  {"id": 11, "firstName": "Hello","parentId": 5},
  {"id": 12, "firstName": "Ana", "parentId": 4}
];

var getNestedChildren = function(arr, id, checked) {

  var out = [];
  for (var i = 0; i < arr.length; i++) {
    if (arr[i].parentId === id && checked.indexOf(arr[i].id) === -1) {
      checked.push(id);
      var children = getNestedChildren(arr, arr[i].id, checked);
      if (children.length) {
        arr[i].children = children;
      }
      out.push(arr[i]);
    }
  }
  return out;

};

console.log(getNestedChildren(arr, 12, []));

【讨论】:

  • 不幸的是 ID:12 它只产生一个孩子,ID 1
  • ID 12 确实有一个子 ID1。 ID1 有四个孩子,他们有孩子等等,直到我们回到 ID 12。
  • 您希望所有的孩子都在同一个数组中?因为找到了孩子,但存储在children 属性中。您只需要一个循环即可将它们全部获取。
  • 没错,在找到顶级父级之前都在同一个数组中,所以在 ID 12 的情况下,列表应该深入填充,直到遇到 ID 12。
  • @Ketus 你是对的。我的代码完全错误。现已更新。
【解决方案2】:

也许这样的东西应该适合你:

function getNestedChildren(arr, parent, visited_list) {
  var out = []
  for(var i in arr) {
    if(!(arr[i].id in visited_list) && (arr[i].parentId == parent)) {

        visited_list[arr[i].id] = true;
        var children = getNestedChildren(arr, arr[i].id, visited_list)

        if(children.length) {
            arr[i].children = children
        }
        out.push(arr[i])
    }
  }
  return out
}

nestedList = getNestedChildren(arr, 1, [])

【讨论】:

  • hm 我认为它会起作用,但是当我从 ID 12 开始时,4 层深还有 ID 12 的对象。有什么想法吗?
【解决方案3】:

您可以标记您已经访问过的条目。基于此,您可以跳过两次处理相同的元素。

当您将children 属性添加到元素时,您可以将其用于此标记目的,前提是您还可以在元素没有子元素时创建此属性。

这是执行此操作的工作代码:

function getNestedChildren(arr, parent) {
  var out = [];
  for(var i in arr) {
    if(arr[i].parentId == parent) {
        if (arr[i].children === undefined) {
            arr[i].children = []
            var children = getNestedChildren(arr, arr[i].id)
            arr[i].children = children
        }
        out.push(arr[i])
    }
  }
  return out
}

var arr = [
    {"id": 1, "firstName": "Macko","parentId": 12},
    {"id": 2, "firstName": "Jess","parentId": 1},
    {"id": 3, "firstName": "Peter","parentId": 1},
    {"id": 4, "firstName": "Lisa", "parentId": 1},
    {"id": 5, "firstName": "Megan","parentId": 1},
    {"id": 6, "firstName": "John", "parentId": 4},
    {"id": 7, "firstName": "Joe", "parentId": 4},
    {"id": 8, "firstName": "Matthew","parentId": 2},
    {"id": 9, "firstName": "Peter","parentId": 2},
    {"id": 10, "firstName": "Dio","parentId": 5},
    {"id": 11, "firstName": "Hello","parentId": 5},
    {"id": 12, "firstName": "Ana", "parentId": 4}
]

getNestedChildren(arr, 1)

// Output the lengths of the children's arrays
document.body.innerHTML = arr.map(function (item) {
    return 'Item ' + item.id + ' has ' + item.children.length + ' children.'
}).join('<br>')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-18
    相关资源
    最近更新 更多