Home > Mobile >  Remove from array if parent property key has been removed
Remove from array if parent property key has been removed

Time:05-17

I am currently trying to remove from an array of objects if the parent gets removed.

My array looks like this:

const items = [
  {
    id: '1'
    generatedFrom: undefined
  },
  {
    id: '2',
    generatedFrom: '1',
  },
  {
    id: '3',
    generatedFrom: '2'
  },
  {
    id: '4',
    generatedFrom: '1'
  }
]

I have a method which filters the objects out based on the id which I am passing into the method:

const removeFromArray = (id: string) => {
   const filtered = items.filter(item => item.id !== id); 
}

This gives me the correct results which I was hoping for in terms of removing the parent object. However, the problem that I am getting is this should have a knock on effect for the remainder of the objects within the array.

If you take the example above:

  • If I remove id 2 then it should delete items[1]
  • As items[2] is generated from id 2 this one should also be removed.
  • items[3] should stay existing as the parent is still there.

This could be a array which has many items within and I am unsure how to approach it.

Example of current issue:

const items = [
  {
    id: 1,
    generatedFrom: undefined
  },
  {
    id: 2,
    generatedFrom: 1
  },
  { 
    id: 3,
    generatedFrom: 2
  },
  {
    id: 4,
    generatedFrom: 3
  },
  {
    id: 5,
    generatedFrom: 4
  },
  {
    id: 6,
    generatedFrom: 1
  }
]

const removeFromArray = (id) => {
 return items.filter(item => item.id !== id && item.generatedFrom !== id);
}

console.log(removeFromArray(2));

// Expected Output:

const expected = [
  {
    id: 1,
    generatedFrom: undefined
  },
  {
    id: 6,
    generatedFrom: 1
  }
]

CodePudding user response:

Since theoretically you could have unlimited level of depth, I don't think one Array.prototype.* call is sufficient here. A beginner's approach would be recursion, but you can tweak that into a queue process:

const items = [
  {
    id: 1,
    generatedFrom: undefined
  },
  {
    id: 2,
    generatedFrom: 1
  },
  { 
    id: 3,
    generatedFrom: 2
  },
  {
    id: 4,
    generatedFrom: 3
  },
  {
    id: 5,
    generatedFrom: 4
  },
  {
    id: 6,
    generatedFrom: 1
  }
];

const removeFromArray=(id:number)=>{
    let queue:number[]=[id];
    let rst=[...items];
    while(queue.length>0){
        let hd=queue.shift();
        rst=rst.filter((item)=>{
          if(item.id==hd){
            return false;
          }
          if(item.generatedFrom==hd){
            queue.push(item.id);
            return false;
          }
          return true;
        });
    }
    return rst;
};

console.log(removeFromArray(2));

Online playground

Removing 2 will give you

[{
  "id": 1,
  "generatedFrom": undefined
}, {
  "id": 6,
  "generatedFrom": 1
}]

CodePudding user response:

You can use a recursive function, I advise you to use a Set in order to avoid infinite loops or repeating deletions:

const items = [
  {
    id: 1,
    generatedFrom: undefined
  },
  {
    id: 2,
    generatedFrom: 1
  },
  { 
    id: 3,
    generatedFrom: 2
  },
  {
    id: 4,
    generatedFrom: 3
  },
  {
    id: 5,
    generatedFrom: 4
  },
  {
    id: 6,
    generatedFrom: 1
  }
]

const ids = new Set();

const deleteById = (id, items) => {
  ids.delete(id);
  let filtered = items.filter(item => {
    if (item.id === id || item.generatedFrom === id) {
      if(item.id) ids.add(item.id);
      return false;
    }
    return true;
  });
  
  const it = ids.values();
  let next = it.next();
  while (!next.done) {
   const value = next.value;
   filtered = deleteById(value, filtered);
   next = it.next();
  }
  
  return filtered;
}


console.log(deleteById(2, items));

CodePudding user response:

I believe you should work on the array object itself instead of multiple loops.

Anyway, you can use recursive method to remove the parent id which is same as removed generatedId. Its short and easy.

See the Snippet below:

const items = [
  {
    id: 1,
    generatedFrom: undefined
  },
  {
    id: 2,
    generatedFrom: 1
  },
  { 
    id: 3,
    generatedFrom: 2
  },
  {
    id: 4,
    generatedFrom: 3
  },
  {
    id: 5,
    generatedFrom: 4
  },
  {
    id: 6,
    generatedFrom: 1
  }
]

const removeFromArray = (removeId, items) => {
  items = items.filter(item => item.id !== removeId);
  let ele = items.find(item=> item.generatedFrom == removeId);

  if(ele){
    return removeFromArray(ele.id, items);
  }else{
    return items;
  }
}
console.log(removeFromArray(2, items));

// Expected Output:

const expected = [
  {
    id: 1,
    generatedFrom: undefined
  },
  {
    id: 6,
    generatedFrom: 1
  }
]

CodePudding user response:

You could try with a recursion:

const items = [ { id: 1, generatedFrom: undefined }, { id: 2, generatedFrom: 1 }, { id: 3, generatedFrom: 2 }, { id: 4, generatedFrom: 3 }, { id: 5, generatedFrom: 4 }, { id: 6, generatedFrom: 1 } ]

const removeFromArray = (id, items) => {
  items = items.filter(x => x.id !== id);  // remove element with id == id
  
  // recursively find orphan objects
  let index = items.findIndex(obj => obj.generatedFrom === id);
  if (index !== -1) {
     let newId = items[index].id;
     items = items.filter(x => x.generatedFrom !== id);
     return removeFromArray(newId, items)
  }
  else return items;
}

console.log(removeFromArray(2, items));

Two steps:

  1. remove item with id === id;
  2. recursively find all the objects that was created from the original id and recall the function by filtering result array.
  • Related