Reputation: 682
I have a JSON parent-child recursive structure made like in the example below.
How can I filter this JSON list to exclude just the object corresponding to a selected index?
familyTree =[
{
name: "parent",
index:"0",
age:"50,
children: [
{
name: "first child",
index:"0.0",
age:"30",
children: [
{
name: "first grandChild",
index:"0.0.0",
age:"5"
},
{
name: "second grandChild",
index: "0.0.1",
age:"2"
}
]
},
{
name: "second child",
index:"0.1",
age:"24",
}
]
}
]
E.g. If I want to exclude the element with index "0.0.1" ,my result will be:
familyTree =[
{
name: "parent",
index:"0",
children: [
{
name: "first child",
index:"0.0",
age:"30",
children: [
{
name: "first grandChild",
index:"0.0.0",
age:"5"
}
]
},
{
name: "second child",
index:"0.1",
age:"24",
}
]
}
]
I've tried to use ES6 function filter() but it's probably the wrong use since it's not working
const elemToRemove= familyTree[0].children[0].children[1]; //index: 0.0.1
familyTree.filter(
(elem) => JSON.stringify(elem) === JSON.stringify(elemToRemove)
);
Thank you for your help
Upvotes: 0
Views: 1893
Reputation: 12920
If you will always be accessing/removing elements by their index you can use it as an address to access the item and return it at the same time as removing it. This solution edits the original array in place.
const indexToRemove = '0.0.1';
const keys = indexToRemove.split('.').map((e, i, a) => a.slice(0, i+1).join('.'));
// ['0', '0.0', '0.0.1']
const removedItem = keys.reduce((a, k, i) => {
if (i !== keys.length-1) {
a = a.find(e => e.index === k).children;
} else {
const ri = a.map(e => e.index).indexOf(k);
a = a.splice(ri, 1);
}
return a;
}, familyTree);
const familyTree =[
{
name: "parent",
index:"0",
age:"50",
children: [
{
name: "first child",
index:"0.0",
age:"30",
children: [
{
name: "first grandChild",
index:"0.0.0",
age:"5"
},
{
name: "second grandChild",
index: "0.0.1",
age:"2"
}
]
},
{
name: "second child",
index:"0.1",
age:"24",
}
]
}
]
const indexToRemove = '0.0.1';
const keys = indexToRemove.split('.').map((e, i, a) => a.slice(0, i+1).join('.'));
const removedItem = keys.reduce((a, k, i) => {
if (i !== keys.length-1) {
a = a.find(e => e.index === k).children;
} else {
const ri = a.map(e => e.index).indexOf(k);
a = a.splice(ri, 1);
}
return a;
}, familyTree);
console.log(removedItem);
console.log(familyTree);
Upvotes: 1
Reputation: 135277
Here's one possibe implementation of filterRec
-
function filterRec (t, f)
{ const many = (t = []) =>
t.flatMap(one)
const one = (t = {}) =>
Boolean(f(t))
? [ { ...t, children: many(t.children) } ]
: []
return many(t)
}
Usage is similar to Array.prototype.filter
-
const result =
filterRec(familyTree, elem => elem.index !== "0.0.1")
console.log(JSON.stringify(result, null, 2))
[
{
"name": "parent",
"index": "0",
"age": "50",
"children": [
{
"name": "first child",
"index": "0.0",
"age": "30",
"children": [
{
"name": "first grandChild",
"index": "0.0.0",
"age": "5",
"children": []
}
]
},
{
"name": "second child",
"index": "0.1",
"age": "24",
"children": []
}
]
}
]
Expand the snippet below to verify the results in your own browser -
function filterRec (t, f)
{ const many = (t = []) =>
t.flatMap(one)
const one = (t = {}) =>
Boolean(f(t))
? [ { ...t, children: many(t.children) } ]
: []
return many(t)
}
const familyTree =
[{name:"parent",index:"0",age:"50",children:[{name:"first child",index:"0.0",age:"30",children:[{name:"first grandChild",index:"0.0.0",age:"5"},{name:"second grandChild",index:"0.0.1",age:"2"}]},{name:"second child",index:"0.1",age:"24"}]}]
const result =
filterRec(familyTree, elem => elem.index !== "0.0.1")
console.log(JSON.stringify(result, null, 2))
Upvotes: 1
Reputation: 2452
Here is a way to solve your problem. The function familyTreeFilterChildrenByIndex
checks the index of each element and also runs itself on any children.
const familyTree =[ { name: "parent", index:"0", age:"50", children: [ { name: "first child", index:"0.0", age:"30", children: [ { name: "first grandChild", index:"0.0.0", age:"5" }, { name: "second grandChild", index: "0.0.1", age:"2" } ] }, { name: "second child", index:"0.1", age:"24", } ] } ]
const familyTreeFilterChildrenByIndex = function (familyTree, indexToRemove) {
const result = []
for (const parent of familyTree) {
if (parent.index === indexToRemove) {
continue
} else if (parent.children) {
result.push({
...parent,
children: familyTreeFilterChildrenByIndex(parent.children, indexToRemove),
})
} else {
result.push(parent)
}
}
return result
}
console.log((familyTreeFilterChildrenByIndex(familyTree, '0.0.1')))
Upvotes: 1