简体   繁体   English

Javascript递归导致循环结构

[英]Javascript recursion caused circular structure

I have the following 2D array cells : 我有以下2D阵列cells

ID  Name    Parent
1   Bob     0
2   Alice   1
3   John    2
4   Jane    2
5   Jenny   3
6   Jonny   2

I want to convert it into nested JSON format, such that each object has the following attributes: 我想将其转换为嵌套的JSON格式,这样每个对象都具有以下属性:

  1. name 名称

  2. Array of children, which includes also objects with names and arrays of children. 子代数组,还包括带有名称和子代数组的对象。 There are no circular nestings in the array; 数组中没有圆形嵌套; a child can't have any of its parents as children. 一个孩子不能有任何父母作为孩子。

Here is the function I wrote: 这是我写的函数:

function getChildren(node){
    console.log('Getting Children for' + node)
    children = []
    for(i = 0;i < cells.length; i++){
        if(cells[i][2] == node){
            cell = cells[i]
            child = {}
            child.name = cell[1]
            child.children = getChildren(cell[0])
            children.push(child)
        }
    }
    return children
}


text = "ID  Name    Parent\n1   Bob     0\n2   Alice   1\n3   John                  2\n4   Jane    2\n5   Jenny     3\n6   Jonny   2\n"

lines = text.split('\n')
cells = []
for(i = 0; i < lines.length; i++){
    cells[i] = lines[i].split(/\ +/)
}

Calling the function on node 6 getChildren(6) , gives this output: 调用节点6 getChildren(6)上的函数,将得到以下输出:

Getting Children for6 让孩子参加6
[] []

Which is correct because node 6 has no children. 这是正确的,因为节点6没有子节点。

But calling the function on nodes with children, for example getChildren(3) , gives: 但是在带有孩子的节点上调用该函数,例如getChildren(3)getChildren(3)得到:

Getting Children for3 让孩子参加3
Getting Children for5 让孩子参加5

 Object children: Array[1] 0: Object children: Array[1] 0: Object children: Array[1] name: "Jenny" length: 1 name: "Jenny" length: 1 name: "Jenny" 

From the console output it seems like it calls the right functions, but why is the object for "jenny" infinitely nested under all children? 从控制台输出看来,它似乎调用了正确的函数,但是为什么“ jenny”的对象无限嵌套在所有子对象下?

I want to end up with a JSON object that I could use JSON.stringify on. 我想结束一个可以使用JSON.stringify的JSON对象。 Calling the function on getChildren(3) gives the error getChildren(3)上调用该函数会产生错误

Uncaught TypeError: Converting circular structure to JSON. 未捕获的TypeError:将圆形结构转换为JSON。

I think this is because the object for Jenny is infinitely nested under each child. 我认为这是因为Jenny的对象无限嵌套在每个孩子下。

Change your function to the following 将功能更改为以下内容

function getChildren(node){
    console.log('Getting Children for' + node)
    var children = []
    for(i = 0;i<cells.length; i++){
        if(cells[i][2] == node){
            var cell = cells[i]
            child = {}
            child.name = cell[1]
            child.children = getChildren(cell[0])
            children.push(child)
        }}
    return children
}

Note the added "var"'s before the variable declarations. 注意变量声明之前添加的“ var”。 This makes sure they are reinitialized instead of persisting through functions calls. 这样可以确保它们被重新初始化,而不是通过函数调用持久化。 That's what was causing your issue. 这就是造成您的问题的原因。

You use global variables, and as a consequence, when you call your function recursively, variables like children and child can get new values. 您可以使用全局变量,并因此,当您递归调用的功能,如儿童儿童的变量可以得到新的价值。 When you come back out of the recursive call, you do: 当您退出递归调用时,您将执行以下操作:

children.push(child)

.. but children will have taken another value than you expect, and so can child also have a different value, both from what they were in the recursive call (or from even deeper into the recursion). ..但子级将获得比您期望的其他值,因此子级也可能具有与递归调用中不同的值(甚至从更深的递归中获得)。

For the same reason the recursive modification of i will lead to problems. 出于同样的原因, i的递归修改将导致问题。

Use var to make your variables local to your function, and it will work: 使用var将变量设为函数的局部变量,它将起作用:

function getChildren(node){
    console.log('Getting Children for' + node)
    var children = []
    for(var i = 0;i<cells.length; i++){
        if(cells[i][2] == node){
            var cell = cells[i]
            var child = {}
            child.name = cell[1]
            child.children = getChildren(cell[0])
            children.push(child)
        }}
    return children
}

 function getChildren(node){ var children = [] for(var i = 0;i<cells.length; i++){ if(cells[i][2] == node){ var cell = cells[i] var child = {} child.name = cell[1] child.children = getChildren(cell[0]) children.push(child) }} return children } var text = "ID Name Parent\\n1 Bob 0\\n2 Alice 1\\n3 John 2\\n4 Jane 2\\n5 Jenny 3\\n6 Jonny 2\\n" var lines = text.split('\\n') var cells = [] for(var i = 0; i< lines.length; i++){ cells[i] = lines[i].split(/\\ +/) } console.log(JSON.stringify(getChildren(0), null, 2)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

if I understand right you can use another way to parse your data: 如果我理解正确,则可以使用另一种方式解析数据:

//separete the values
var input = [
    [1,   'Bob',     0],
    [2,   'Alice',   1],
    [3,   'John',    2],
    [4,   'Jane',    2],
    [5,   'Jenny',   3],
    [6,   'Jonny',   2]
];

var entities = []; //I belive that the ids are uniq

for (var i = 0; i < input.length; i++){
    var id = input[i][0];
  entities[id] = {
    id: id, 
    name: input[i][1], 
    children : [], 
    parent: input[i][2]
  };
}

for (var i in entities){
    var current = entities[i];
  var parent = entities[current.parent];
  delete current.parent;

  if (parent){
        parent.children.push(current);
  }
}

By this way you can find the particular element from the entities array by indexes, or at the begin of parsing get the root element (the element which does not contain its parent in the elements array) 通过这种方式,您可以通过索引从实体数组中找到特定的元素,或者在解析开始时获取根元素(在elements数组中不包含其父元素的元素)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM