javascript - 对深层嵌套对象进行递归迭代以查找父对象

标签 javascript ecmascript-6

我有一个带有子项的数据树结构:

{  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 中所选项目的已知文本标题以及用户想要插入的数据。我无法找到一种递归算法来将新数据添加到树的正确级别。

以下是我思考问题并尝试对其进行伪编码的列表:

输入:

  1. 树(上面的数据)
  2. 来自 DOM 中被点击项目的parentTitle

输出:

  1. 已插入项目的树

步骤:

  1. 确定最高使用的 ID 以了解下一个唯一 ID 是什么
  2. 检查当前数据级别是否与父级职位匹配
  3. 如果匹配,则在新数据中设置 id 和parent_id 并推送到父级的子级
  4. 如果不匹配,则检查当前级别数据是否有子级
  5. 如果当前级别有子级,则需要为每个子级重复步骤 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/

相关文章:

javascript获取值包含特定字符串的元素

javascript - 无法正确指定 CORS 请求的 header

javascript - 我将如何验证选择子集中的唯一选择?

javascript - 当值为 null 时使用扩展运算符

javascript - webpack 中的循环依赖

javascript - SAPUI5 创建带有日期的 OData 实体 - 生成以 CX_SXML_PARSE_ERROR 结尾的错误请求负载

javascript - 在 HTML 中嵌入 XML

javascript - React组件类变量访问

javascript - 将 ES6 类方法作为要在函数内部调用的函数参数传递

javascript - 动态更新 Angular2 指令中自定义属性的值