Skip to content Skip to sidebar Skip to footer

Remove Item Recusively From Tree

I'm trying to create a tree component. But I dont know how remove a item recursively inside a tree. Each item its created dinamically and I would like remove an item/branch of the

Solution 1:

Although this can be done in a single function, it's a lot cleaner and less repetitive if you write this with mutual recursion. Here we write two functions. One removes the element from an array, replacing it with any children it might have. The other processes a single object, removing the id from it (and from any of its children.) Our main function here is removeElement, which will call removeElementFromArray on our input if the initial data is an array or call it against any children if the initial data is a plain object.

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}

Solution 2:

Hope this will help

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;

function removeElement(data, id) {
  return data
    .filter((dt) => {
      return dt.id !== id;
    })
    .map((dt) => {
      if (dt.children) {
        return {
          ...dt,
          children: removeElement(dt.children, id),
        };
      }
      return dt;
    });
}
console.log(removeElement(data, id));

Solution 3:

I agree with Scott that mutual recursion is a great fit for this problem. I would divide the responsibilities slightly different however -

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}

In addition, this answer cares less about the optional children property and as a result it will add { ...t, children: [] } to any t without children.


I admire Scott for his exacting approach and I wondered how I might be able to preserve the children-less leaf nodes -

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}

Post a Comment for "Remove Item Recusively From Tree"