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:
2 then it should delete items[1]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
}
]
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));
Removing 2 will give you
[{
"id": 1,
"generatedFrom": undefined
}, {
"id": 6,
"generatedFrom": 1
}]
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:
id === id;id and recall the function by filtering result array.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));