如何阻止这种递归函数?

时间:2016-04-16 15:58:17

标签: javascript arrays circular-reference

我有javascript数组,其中每个项都引用了parent,它们可以循环(循环引用)。例如:

[
        {"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
}

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

我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:1)

也许这样的事情对你有用:

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, [])

答案 1 :(得分:1)

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

当您将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>')

答案 2 :(得分:1)

checked数组保持已调用所有对象(父项)id的{​​{1}}。

如果当前孩子的getNestedChildren在该数组中,请不要将其作为孩子包含。

id