首页 > 解决方案 > 无法递归删除对象数组中的对象

问题描述

const arr = [
  {
    id: "8bfc-2b82-68ad-fb78",
    name: "inventory",
    type: "directory",
    path: "inventory/",
    children: [
      {
        id: "bccf-3788-6ec9-ba33",
        name: "inventory.yaml",
        type: "file",
        path: "inventory/inventory.yaml",
      },
    ],
  },
  {
    id: "4a28-4d63-6c30-4569",
    name: "model",
    type: "directory",
    path: "model/",
    children: [
      {
        id: "21d1-f4d2-e1c5-34b0",
        name: "model.yaml",
        type: "file",
        path: "model/model.yaml",
      },
    ],
  },
];








  function _worktreeItemDelete({ detail }) {
    const currentId = detail.item.id;
    const filtered = this.tree.filter(entry => entry.id !== currentId);
    const updTree = filtered.map(entry => {
      if (!entry.children) return entry;
      return {...entry, children: this._worktreeItemDelete(entry.children, currentId)};
    });
    console.log(updTree);
    this.set("tree", updTree);
  }

这就是我正在做的。currentId我正在捕捉作为事件属性值。我现在遇到的问题是:

Uncaught RangeError: Maximum call stack size exceeded

如果我理解正确,递归并没有停止,正在寻找一种方法来处理这个问题。感谢你的帮助。

标签: javascriptrecursioneventsecmascript-6frontend

解决方案


修复功能

你很近。问题是您将一个对象传递给初始删除调用,提取嵌套属性id以正确使用,但是当您进行递归调用时,您只使用该 id,而不是整个对象。

最快的解决方法可能是保留对该对象的引用,而不是在参数中对其进行解构。我对上下文没有足够的理解来恰当地命名它,所以我就叫它foo。然后我们可以传递foo给递归调用,它就可以工作了。

通过该修复,您的函数的变体将正常工作:

function _worktreeItemDelete(tree, foo) {
  const currentId = foo.detail.item.id;
  const filtered = tree.filter(entry => entry.id !== currentId);
  const updTree = filtered.map(entry => {
    if (!entry.children) return entry;
    return {...entry, children: _worktreeItemDelete(entry.children, foo)};
  });
  return updTree
}

const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]

console .log (
  _worktreeItemDelete (arr, {detail: {item: {id: 'bccf-3788-6ec9-ba33'}}})
)
.as-console-wrapper {max-height: 100% !important; top: 0}

请注意,我将其更改为纯函数而不是方法,因此跳过this.set("tree", updTree)、添加tree参数和删除this引用。它们应该很容易放回去。

但是,上面并没有解释你描述的递归深度错误。我会期待更多类似的东西

Cannot read property 'item' of undefined

所以可能会发生一些额外的事情。

另一种方法

我会以不同的方式编写此代码。我会使用一个通用版本的树过滤函数,并将它传递给节点选择的谓词。

我的版本可能如下所示:

const deepFilter = (pred) => (xs) =>
  xs .flatMap (({children = [], ...rest}) => 
    pred (rest)
      ? [{... rest, children: deepFilter (pred) (children)}]
      : []
  )

const removeById = ({detail: {item: {id: target}}}) => 
  deepFilter (({id}) => id !== target)

const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]

console .log (
  removeById ({detail: {item: {id: 'bccf-3788-6ec9-ba33'}}}) (arr)
)
.as-console-wrapper {max-height: 100% !important; top: 0}

请注意,这deepFilter是通用的。它适用于后代节点位于属性中的任何树children。(有关可让您配置此属性的更通用版本,请参阅另一个答案。)

所以这里的自定义代码就是removeById. 在我看来,这是一场不错的胜利。

如果它很重要,我们可以——以额外的复杂性为代价——选择仅children在数据不为空时包含节点。如果您想要它并需要帮助,只需添加评论即可。


推荐阅读