Recursively Filter And Delete Item In Array Of Objects
Solution 1:
I would try to build this on top of a reusable function. I abstracted a deepFilter
from another answer so that we can configure the name of the child nodes (most commonly 'children'
, here 'layers'
, but I've seen many others.) The returned function takes a predicate and returns another function which takes an array, and recursively keeps only those nodes for which the predicate returns true.
Using this, we can write removeById
by passing 'layers'
to deepFilter
along with a predicate that checks if a node's id
fails to match our target. It looks like this
constdeepFilter = (childProp) => (pred) =>(xs) =>
xs .flatMap (({[childProp]: children = [], ...rest}) =>
pred (rest)
? [{... rest, [childProp]: deepFilter (childProp) (pred) (children)}]
: []
)
constremoveById = (target) =>
deepFilter ('layers') (({id}) => id !== target)
const payload = [{id: 1, name: "Shrek", lock: false, checked: false, selected: false, layers: [/* onions have layers */]}, {id: 2, name: "Fiona", lock: false, checked: false, selected: false, layers: [{id: 4, name: "Lord Farquad", lock: false, checked: false, selected: false, layers: [{id: 5, name: "Prince Charming", lock: false, checked: false, selected: false, layers: []}]}]}, {id: 3, name: "Donkey", lock: false, checked: false, selected: false, layers: [/* parfaits have layers */]}]
console .log (
removeById (5) (payload)
)
.as-console-wrapper {max-height: 100%!important; top: 0}
If we prefer to call in this manner: removeById (payload, 5)
, then we can simply write
constremoveById = (payload, target) =>
deepFilter ('layers') (({id}) => id !== target) (payload)
The big advantage here is that we can write a reusable function in a simple manner, and find uses all over the place for it, making our custom code extremely trivial.
Solution 2:
you were close.
- based on your expected output I think you want to return
o.id != 5
- if a node has layers then you need to assign those layers to the filtered value of themselves
o.layers = o.layers.filter(f)
functionf(o) {
if (o.layers.length) {
o.layers = o.layers.filter(f)
}
return o.id != 5;
}
let filtered = layers.filter(f);
Solution 3:
Here is an iterative solution using object-scan
// const objectScan = require('object-scan');const data = [{ id: 1, name: 'Shrek', lock: false, checked: false, selected: false, layers: [] }, { id: 2, name: 'Fiona', lock: false, checked: false, selected: false, layers: [{ id: 4, name: 'Lord Farquad', lock: false, checked: false, selected: false, layers: [{ id: 5, name: 'Prince Charming', lock: false, checked: false, selected: false, layers: [] }] }] }, { id: 3, name: 'Donkey', lock: false, checked: false, selected: false, layers: [] }];
const remove = objectScan(['**(^layers$)'], {
rtn: 'bool',
abort: true,
useArraySelector: false,
filterFn: ({ parent, property, value, context }) => {
if (value.id === context) {
parent.splice(property, 1);
returntrue;
}
returnfalse;
}
});
console.log(remove(data, 5));
// => trueconsole.log(data);
// => [ { id: 1, name: 'Shrek', lock: false, checked: false, selected: false, layers: [] }, { id: 2, name: 'Fiona', lock: false, checked: false, selected: false, layers: [ { id: 4, name: 'Lord Farquad', lock: false, checked: false, selected: false, layers: [] } ] }, { id: 3, name: 'Donkey', lock: false, checked: false, selected: false, layers: [] } ]
.as-console-wrapper {max-height: 100%!important; top: 0}
<scriptsrc="https://bundle.run/object-scan@14.3.1"></script>
Disclaimer: I'm the author of object-scan
Post a Comment for "Recursively Filter And Delete Item In Array Of Objects"