Skip to content Skip to sidebar Skip to footer

Recursively Filter And Delete Item In Array Of Objects

I'm trying to deep filter until specific object with id found. I've taken these references, Recursively filter array of objects Filter items in array of objects Recursively filter

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"