0

I want to be able to remove an object from an array of objects that have children. I thought immediately this is a job for recursion, but I am unable to get my recursion function to work properly. I thought of using reduce to rebuild the data structure without the object that I want to remove. The function should accept two parameters the array of nested objects and an Id.

My requirements are: remove the node and all children below.

At first glance, this seems easy, but the challenge I find is removing a child and keeping the entire data structure intact. Deleting the parent by filtering based on the id is trivial, but the nested children pose a problem.

My data structure looks like this:

const data = [{
  id: 'BFQEA1W2RK1YRETZ9343',
  name: 'Cover',
  activityId: 'BFQEA1W2RK1YRETZ9343',
  nodeType: 'activity',
  suppressed: true,
  hidden: true
},
{
  children: [
    {
      id: 'ZNRAE749BSD0CTGHY888',
      name: 'Consultants, Reviewers, and National Geographic Exploration',
      activityId: 'ZNRAE749BSD0CTGHY888',
      nodeType: 'activity',
      suppressed: false,
      hidden: false
    },
    {
      id: 'JZLS37EVZQM22H9Q4655',
      name: 'The National Geographic Approach',
      activityId: 'JZLS37EVZQM22H9Q4655',
      nodeType: 'activity',
      suppressed: false,
      hidden: false
    },
  ]
}
]

If I pass this Id(ZNRAE749BSD0CTGHY888) to the function my expected data result should be:

const expected =  [{
  id: 'BFQEA1W2RK1YRETZ9343',
  name: 'Cover',
  activityId: 'BFQEA1W2RK1YRETZ9343',
  nodeType: 'activity',
  suppressed: true,
  hidden: true
},
{
  children: [

    {
      id: 'JZLS37EVZQM22H9Q4655',
      name: 'The National Geographic Approach',
      activityId: 'JZLS37EVZQM22H9Q4655',
      nodeType: 'activity',
      suppressed: false,
      hidden: false
    },
  ]
}
]

My function looks like this:

 findNode = (id, arr) => {
    return arr.reduce((a, item) => {
      // if (item.id === id) {
      //   console.log('here');
      //   return item;
      // }
      if (item.id !== id) {
        a.push(item);
      }
      if (item.children) {
        return this.findNode(id, item.children);
      }
    }, []);
  };

The function's reduce accumulator is undefined, but I am unsure why. It should be making a new array. What am I missing here?

In my head, this seems to work, but it fails. Maybe my approach is completely off. How should I go about solving this?

8
  • 1
    Do your want to remove the node or make a new array with the node filtered out Commented Dec 30, 2018 at 17:43
  • make a new array with the node filtered out. Commented Dec 30, 2018 at 17:55
  • See stackoverflow.com/questions/38132146/… Commented Dec 30, 2018 at 18:03
  • @danh I will take a look. Commented Dec 30, 2018 at 18:04
  • Looking at this a little closer…none of the objects that have id properties have children. So it's not clear what you are trying to filter when you say remove the node and all children below. Commented Dec 30, 2018 at 18:11

1 Answer 1

2

In your code you are not returning the accumulator. That's why you're getting undefined. And there's no reason to recurse over children of items that you don't push, so you should nest the recursion under the if.

You can loop over you root array with reduce(). If the id matches, just return and continue. Other wise you can recursively pass the children the filter and push to the return array:

const data = [{id: 'BFQEA1W2RK1YRETZ9343',name: 'Cover',activityId: 'BFQEA1W2RK1YRETZ9343',nodeType: 'activity',suppressed: true,hidden: true},{children: [{id: 'ZNRAE749BSD0CTGHY888',name: 'Consultants, Reviewers, and National Geographic Exploration',activityId: 'ZNRAE749BSD0CTGHY888',nodeType: 'activity',suppressed: false,hidden: false},{id: 'JZLS37EVZQM22H9Q4655',name: 'The National Geographic Approach',activityId: 'JZLS37EVZQM22H9Q4655',nodeType: 'activity',suppressed: false,hidden: false},]}]


function filterID(id, data) {
  return data.reduce((arr, item) => {
    if (item.id != id) {
      if (item.children) item.children = filterID(id, item.children)
      arr.push(item)
    }
    return arr  // <<-- need to return the accumulator  
  }, [])
}
console.log(filterID("ZNRAE749BSD0CTGHY888", data))

Sign up to request clarification or add additional context in comments.

4 Comments

This is what I wanted. Thank you so much.
I was close just forgot to return the accumulator.
Yeah, it's so easy to forget that.
Thank you so much. I really appreciate you taking the time to help me on a Sunday.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.