我有一个带有孩子的数据树结构:
{ 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中的选定项目以及用户要插入的数据具有已知的文本标题。我在寻找一种递归算法时遇到了麻烦,该算法将允许我将新数据添加到树的正确级别。
以下是我对问题进行思考并尝试对其进行伪编码的列表:
输入:
输出:
步骤:
这是我的代码:
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;
}
因此,如果用户在单击“狗”的添加按钮时键入了“猫”,则将创建一个新对象
{
id: 7,
name: "Cat",
parent_id: 1,
children: []
}
将被插入数据树中第一级“ Dog”对象的子级。
答案 0 :(得分:1)
如果要使用递归解决方案,则应修改defineParent方法,使其在树中向下搜索。 不确定这正是您要搜索的内容,但我希望您能大致了解
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。
答案 1 :(得分:0)
如果可以使用Lodash + Deepdash,则:
let child = {
name: "Cat",
children: []
};
let maxUsedId=-1;
_.eachDeep([data],(val)=>{
if(val.id>maxUsedId){
maxUsedId = val.id;
}
if(val.name==parentName){
val.children.push(child);
child.parent_id = val.id;
}
},{tree:true});
child.id=maxUsedId+1;
答案 2 :(得分:0)
不大喜欢重新发明轮子,特别是在算法方面。这是使用object-scan解决问题的方法。我们将它用于数据处理,因为一旦您将其包裹起来,它就会非常强大
java -jar [mvn-created-jar-file-name] --spring.profiles.active=dev