我有一个带有子项的数据树结构:
{ id: 1,
name: "Dog",
parent_id: null,
children: [
{
id: 2,
name: "Food",
parent_id: 1,
children: []
},
{
id: 3,
name: "Water",
parent_id: 1,
children: [
{
id: 4,
name: "Bowl",
parent_id: 3,
children: []
},
{
id: 5,
name: "Oxygen",
parent_id: 3,
children: []
},
{
id: 6,
name: "Hydrogen",
parent_id: 3,
children: []
}
]
}
]
}
任何子数据对象都可以有更多子对象,如上面的数据所示。这表示一个 DOM 结构,用户可以从中选择一个项目来添加子项。
我有 DOM 中所选项目的已知文本标题以及用户想要插入的数据。我无法找到一种递归算法来将新数据添加到树的正确级别。
以下是我思考问题并尝试对其进行伪编码的列表:
输入:
- 树(上面的数据)
- 来自 DOM 中被点击项目的parentTitle
输出:
- 已插入项目的树
步骤:
- 确定最高使用的 ID 以了解下一个唯一 ID 是什么
- 检查当前数据级别是否与父级职位匹配
- 如果匹配,则在新数据中设置 id 和parent_id 并推送到父级的子级
- 如果不匹配,则检查当前级别数据是否有子级
- 如果当前级别有子级,则需要为每个子级重复步骤 2+,直到找到匹配项
这是我的代码:
function askUserForNewItem(e) {
const tree = getTree(); // returns above tree data structure
const name = prompt( 'Enter new item’s name:' ); // user input to match and insert as new item in tree
const clickedTitle = getClickedTitle(e); // returns string title of clicked on item from DOM - for example "Dog" or "Bowl"
const parent = determineParent(tree, clickedTitle);
const parent_id = parent[0].id;
// TODO - needs to set real unique id (highest unused id)
const newId = 101; // hard coded for now, needs to be dynamic
// TODO - needs to insert into correct level of children array in tree
return tree.children.push({ id: newId, name, emoji, children: [], parent_id: parent_id });
}
function determineParent(tree, clickedTitle) {
if(tree.children.length === 0) {
return false;
}
let treeLevel = tree;
let parent = [];
while(treeLevel.children.length !== 0) {
parent = treeLevel.children.filter(child => child.name === clickedTitle);
if(parent.length !== 0) {
break;
}
else {
// what to do here to make this recursive?
}
}
return parent;
}
因此,如果用户在单击“Dog”的添加按钮时键入“Cat”,则会创建一个新对象
{
id: 7,
name: "Cat",
parent_id: 1,
children: []
}
将插入到数据树中第一级“Dog”对象的子级中。
最佳答案
如果您想要递归解决方案,您应该修改确定Parent 方法,以便它沿着树向下搜索。 不确定这正是您正在寻找的内容,但我希望您能了解总体思路
function determineParent(curNode, clickedTitle) {
if(curNode.name===clickedTitle)
return curNode; // found the parent node with the correct clickedTitle
// not found yet, do a recusive search down the tree.
for(const node of curNode.children) {
return determineParent(node,clickedTitle);
}
return null; // not found.
}
这个想法是从最顶层的节点(curNode)开始,首先确定它是否是正确的父节点,如果不是,则取第一个子节点,看看它是否匹配,如果不匹配,则向下搜索它的子节点,依此类推。
在处理递归时,可能需要处理可能遇到循环引用的情况,考虑这样一种情况:一个节点有一个子节点指向父节点或祖父节点,递归方法将永远运行(在现实生活中)它会耗尽堆栈空间并抛出异常)。
其中一种方法是包含一个安全计数器,该计数器在每次递归调用时都会减少,然后在达到零时退出。
function determineParent(curNode, clickedTitle, safeGuard) {
if(curNode.name===clickedTitle)
return curNode; // found the parent node with the correct clickedTitle
if(safeGuard===0)
return null; // bail out
// not found yet, do a recusive search down the tree.
for(const node of curNode.children) {
return determineParent(node,clickedTitle,--safeGuard);
}
return null; // not found.
}
然后这样调用它
this.determineParent(tree,"title",100);
将搜索次数限制为 100。
关于javascript - 对深层嵌套对象进行递归迭代以查找父对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55080232/