Javascript递归导致循环结构
Posted
技术标签:
【中文标题】Javascript递归导致循环结构【英文标题】:Javascript recursion caused circular structure 【发布时间】:2017-03-03 01:49:40 【问题描述】:我有以下二维数组cells
:
ID Name Parent
1 Bob 0
2 Alice 1
3 John 2
4 Jane 2
5 Jenny 3
6 Jonny 2
我想把它转换成嵌套的 JSON 格式,这样每个对象都有以下属性:
姓名
子数组,其中还包括具有名称的对象和子数组。数组中没有循环嵌套;孩子不能有任何父母作为孩子。
这是我写的函数:
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(/\ +/)
在节点 6 getChildren(6)
上调用函数,得到以下输出:
让孩子6岁 []
这是正确的,因为节点 6 没有子节点。
但是在有子节点的节点上调用函数,例如getChildren(3)
,给出:
让孩子为 3 让孩子 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"
从控制台输出看来,它调用了正确的函数,但为什么“jenny”的对象无限嵌套在所有子项下?
我想最终得到一个可以使用 JSON.stringify
的 JSON 对象。在getChildren(3)
上调用函数会报错
未捕获的 TypeError:将循环结构转换为 JSON。
我认为这是因为 Jenny 的对象无限嵌套在每个孩子之下。
【问题讨论】:
请以合法的 javascript 数据定义或字符串格式显示您开始使用的实际 Javascript 数据结构以及您希望最终得到的数据结构。显示一个表格并不能准确地告诉我们它在代码中的结构。我们可以猜测,但你应该透露足够的信息,我们不必猜测。 它在小提琴链接中,我从一个解析成表格的字符串开始,最后我想将它转换为 json,每个对象都有一个名称,以及一个子数组,它们也是具有名称的对象和子数组 根据本网站的指南,它应该直接粘贴到您的问题中,而不仅仅是在 jsFiddle 链接中。外部链接会随着时间的推移而改变或消失,从而破坏问题的最重要内容,从而使问题作为长期参考的用处大大降低。另外,您是否意识到 JSON 是一种字符串格式,而不是一种对象格式。这真的是你想要的吗?您应该显示您开始的确切数据定义和您想要结束的确切数据定义,然后您只需要几句话就可以 100% 清楚。 全局变量可能也无济于事,尤其是考虑到您使用的是递归函数。 好的,我添加了完整的代码,以及我想要的最终输出 【参考方案1】:将您的功能更改为以下
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
注意变量声明前添加的“var”。这确保它们被重新初始化,而不是通过函数调用持续存在。这就是导致您的问题的原因。
【讨论】:
【参考方案2】:您使用全局变量,因此,当您递归调用函数时,children 和 child 等变量可以获得新值。当您退出递归调用时,您可以:
children.push(child)
.. 但是 children 将采用另一个值而不是您预期的值,因此 child 也可以具有与递归调用中的值不同的值(或者从更深层次的递归)。
出于同样的原因,i的递归修改会导致问题。
使用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;
【讨论】:
感谢您解释var
部分,但是当我在第一个父级上调用该函数时:JSON.stringify(getChildren(0))
输出不包括具有父级 John 的子 Jenny 它给出:"["name":"Bob","children":["name":"Alice","children":["name":"John","children":[],"name":"Jane","children":[],"name":"Jonny","children":[]]]]"
我不明白。我在答案中添加了一个 sn-p,如果您使用参数 0 调用函数,则表明 Jenny 在输出中。【参考方案3】:
如果我理解正确,您可以使用另一种方式来解析您的数据:
//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);
通过这种方式,您可以通过索引从实体数组中找到特定元素,或者在解析开始时获取根元素(元素数组中不包含其父元素的元素)
【讨论】:
以上是关于Javascript递归导致循环结构的主要内容,如果未能解决你的问题,请参考以下文章