尝试使用递归从嵌套的 javascript 对象树中提取项目
Posted
技术标签:
【中文标题】尝试使用递归从嵌套的 javascript 对象树中提取项目【英文标题】:Trying to extract items from a nested javascript object tree using recursion 【发布时间】:2020-09-26 10:10:58 【问题描述】:我正在尝试学习递归,我有一个代码尝试提取所有父名称,如果他们有孩子,则将它们推送到数组中。
我的问题是我可以打印出所有的父母,但似乎只能推出 5 个中的 2 个。
function printChildrenRecursive(t)
let hasChildren = []
if (t.children.length === 0)
return
t.children.forEach(child =>
if (child.children.length > 0)
console.log(child.name)
hasChildren.push(child.name)
printChildrenRecursive(child)
)
return hasChildren
const tree =
name: 'John',
children: [
name: 'Jim',
children: [
name: 'Joe',
children: [
name: 'Lee',
children: []
]
]
,
name: 'Zoe',
children: [
name: 'Kyle',
children: [
name: 'Tony',
children: []
]
,
name: 'Sophia',
children: [
name: 'Thor',
children: []
]
]
]
let res = printChildrenRecursive(tree)
console.log(res);
console.log 输出
Jim
Joe
Zoe
Kyle
Sophia
但是 hasChildren.push 只输出
(2) ["Jim", "Zoe"]
【问题讨论】:
IsprintChildrenRecursive
是一个奇怪的名字,它应该返回一个父数组。
我知道,我只是在学习有关打印儿童的教程,但在尝试修改代码时忘记了它。
【参考方案1】:
有两个地方你没有处理好应该返回的数组:
在基本情况下,不只是return
,而是return []
在递归的情况下,不要忽略递归调用返回的值,而是将其附加到当前数组中。
这里是更正:
function printChildrenRecursive(t)
let hasChildren = [];
if (t.children.length === 0)
return []; // always return an array!
t.children.forEach(child =>
if (child.children.length > 0)
console.log(child.name);
hasChildren.push(child.name);
// add the returned array:
hasChildren.push(...printChildrenRecursive(child));
)
return hasChildren;
const tree = name: 'John',children: [name: 'Jim',children: [name: 'Joe',children: [name: 'Lee',children: []]],name: 'Zoe',children: [name: 'Kyle',children: [name: 'Tony',children: []],name: 'Sophia',children: [name: 'Thor',children: []]]];
let result = printChildrenRecursive(tree);
console.log(result);
替代解决方案
该算法不返回根节点,因为它专注于 children -- 这可能是有意的。
输出顺序也是广度优先和深度优先的混合。更常见的递归顺序是深度优先顺序——比如预排序。
为什么不使用生成器。
这是一个实现:
function *dfs(node)
// If you want to include leaves, remove the condition:
if (node.children.length) yield node.name;
for (let child of node.children) yield *dfs(child);
const tree = name: 'John',children: [name: 'Jim',children: [name: 'Joe',children: [name: 'Lee',children: []]],name: 'Zoe',children: [name: 'Kyle',children: [name: 'Tony',children: []],name: 'Sophia',children: [name: 'Thor',children: []]]];
let result = Array.from(dfs(tree));
console.log(result);
【讨论】:
约翰呢?应该也加了吧? @Sergey,显然询问者的意图不是获得根。他们的函数名暗示了这一点。【参考方案2】:Trincot 已经说明了您的实施有什么问题。
我想指出,这可以写得更简单。这是一个简单的递归函数来收集所有父节点的名称:
const parents = (name, children) =>
children .length > 0
? [name, ... children .flatMap (parents)]
: []
const tree = name: 'John', children: [name: 'Jim', children: [name: 'Joe', children: [name: 'Lee', children: []]], name: 'Zoe', children: [name: 'Kyle', children: [name: 'Tony', children: []], name: 'Sophia', children: [name: 'Thor', children: []]]]
console .log (parents (tree))
如果某些节点可能没有children
属性,那只是稍微复杂一点:
const parents = (name, children) =>
(children || []) .length > 0
? [name, ... children .flatMap (parents)]
: []
如果您的要求是打印它们,那么您可以调用它并打印结果。我建议您养成将 I/O 与逻辑核心分开的习惯。
【讨论】:
以上是关于尝试使用递归从嵌套的 javascript 对象树中提取项目的主要内容,如果未能解决你的问题,请参考以下文章
如何递归搜索对象树并使用 JavaScript/Prototype 1.7 基于键/值返回匹配的对象