从树中删除性地删除项目

时间:2020-06-04 07:58:23

标签: javascript recursion

我正在尝试创建一个树组件。但是我不知道如何递归地删除树中的项目。

每个项目都是动态创建的,我想在每个级别中删除树的一个项目/分支。

问题在于,当我选择和选择项目并且没有孩子时,我必须找到他的父母并删除选择的项目。但是,如果所选项目有孩子,我必须找到他的父母,获取所选项目的所有孩子,更新所有孩子的parentId,添加到父项并删除所选项目。递归地执行所有这些操作并返回更新的数组。

const data = [
  {id: 1, title: 'foo', children: [
    {id: 11, parentId: 1, title: 'bar',},
    {id: 12, parentId: 1, title: 'baz', children: [
      {id: 121, parentId: 12, title: 'qux'},
      {id: 122, parentId: 12, title: 'quz'}
    ]},
    {id: 13, parentId: 1, title: 'corge'}
  ]},
  {id: 2, title: 'grault'}
];

const id = 12;
console.log (removeElement(data, id));

结果应为:

const data = [
  {id: 1, title: 'foo', children: [
    {id: 11, parentId: 1, title: 'bar', children: [
      {id: 121, parentId: 11, title: 'qux'},
      {id: 122, parentId: 11, title: 'quz'}
    ]},
    {id: 13, parentId: 1, title: 'corge'}
  ]},
  {id: 2, title: 'grault'}
];

3 个答案:

答案 0 :(得分:2)

尽管这可以通过单个函数完成,但是如果您使用mutual recursion编写代码,它将更加整洁且重复性更低。在这里,我们编写两个函数。可以从数组中删除该元素,将其替换为它可能具有的所有子元素。另一个处理单个对象,并从其中(及其任何子元素中删除ID)。这里的主要功能是removeElement,如果初始数据是数组,它将在我们的输入上调用removeElementFromArray或如果初始数据是普通对象,则针对任何子项调用它。

const removeElementFromArray = (arr, id) =>
  arr .flatMap (
    o => o.id === id
      ? [... (o .children || []).map (o => removeElement (o, id))]
      : [removeElement (o, id)]
  )

const removeElement = (obj, id) => 
  Array .isArray (obj)
    ? removeElementFromArray (obj, id)
    : {... obj, ... (obj .children ? {children: removeElementFromArray (obj .children, id)} : {}) }


const data = [
  {id: 1, title: 'foo', children: [
    {id: 11, title: 'bar'},
    {id: 12, title: 'baz', children: [
      {id: 121, title: 'qux'},
      {id: 122, title: 'quz'}
    ]},
    {id: 13, title: 'corge'}
  ]},
  {id: 2, title: 'grault'}
];

console .log (removeElement (data, 121)) // 121 removed
console .log (removeElement (data, 12))  // 12 removed; 121 and 122 moved to 1
console .log (removeElement (data, 1))   // 1 removed; 11, 12, 13 moved to root
console .log (removeElement (data, 42))  // No change
.as-console-wrapper {min-height: 100% !important; top: 0}

答案 1 :(得分:1)

希望这会有所帮助

repeat

答案 2 :(得分:1)

我同意Scott的观点,相互递归非常适合此问题。但是,我将职责划分为略有不同-

const remove = (t = [], id = 0) =>
  t.flatMap(v => remove1(v, id))

const remove1 = ({ children = [], ...t }, id = 0) => // "remove one"
  t.id === id
    ? remove(children, id)
    : [ { ...t, children: remove(children, id) } ]

const data = [
  {id: 1, title: 'foo', children: [
    {id: 11, title: 'bar'},
    {id: 12, title: 'baz', children: [
      {id: 121, title: 'qux'},
      {id: 122, title: 'quz'}
    ]},
    {id: 13, title: 'corge'}
  ]},
  {id: 2, title: 'grault'}
];

console.log(remove(data, 121))
console.log(remove(data, 12))
console.log(remove(data, 1))
console.log(remove(data, 42))
.as-console-wrapper {min-height: 100% !important; top: 0}

此外,此答案不太关心可选的children属性,因此,它将为没有{ ...t, children: [] }的任何t添加children


我很欣赏Scott的严格方法,我想知道如何才能保留少children的叶子节点-

const identity = x => x

const update = (t = {}, k = "", f = identity) => // <- immutable update
  t[k] == null
    ? t
    : { ...t, [k]: f(t[k]) }

const remove = (t = [], id = 0) =>
  t.flatMap(v => remove1(v, id))

const remove1 = (t = {}, id = 0) => 
  t.id === id
    ? remove(t.children, id)
    : [ update(t, "children", c => remove(c, id)) ] // <-- update

const data = [
  {id: 1, title: 'foo', children: [
    {id: 11, title: 'bar'},
    {id: 12, title: 'baz', children: [
      {id: 121, title: 'qux'},
      {id: 122, title: 'quz'}
    ]},
    {id: 13, title: 'corge'}
  ]},
  {id: 2, title: 'grault'}
];

console.log(remove(data, 121))
console.log(remove(data, 12))
console.log(remove(data, 1))
console.log(remove(data, 42))
.as-console-wrapper {min-height: 100% !important; top: 0}

相关问题