Remove Item Recusively From Tree
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"