I have a structure like this:
const tree = [
{
"a": "1",
"children": [
{
"a": "11",
"children": [
{ "a": "111", "p": "me" },
{ "a": "112" }
]
},
{ "a": "111", "p": "me" }
]
},
{ "a": "2" },
{ "text": "3", "p": "me" }
]
And I'm trying to filter the tree by p: "me"
, however, I keep bumping into the parent and can't get past it.
My desired output is something in these lines:
const res = filter(tree, "p", "me")
console.log(res)
/*
[
{
"a": "1",
"children": [
{
"a": "11",
"children": [
{ "a": "111", "p": "me" },
]
},
{ "a": "111", "p": "me" }
]
},
{ "text": "3", "p": "me" }
]
*/
I've tried other solutions and tweak them (like this one), but I'm struggling
CodePudding user response:
Check my comments in code.
The trick is to know when to go into recursion to go deeper in the tree and when to return the true
/false
for the JS filter()
method.
const tree = [
{
"a": "1",
"children": [
{
"a": "11",
"children": [
{ "a": "111", "p": "me" },
{ "a": "112" }
]
},
{ "a": "111", "p": "me" }
]
},
{ "a": "2" },
{ "text": "3", "p": "me" }
]
const filter = (array, property, value) => {
// Filter an array...
return array.filter((object) => {
// If an object of the array has a 'children'
if(object.children){
// It goes into recursion to set the filtered 'children'
object.children = filter(object.children, property, value)
// Then returns true if the children array is not empty
return object.children.length
}
// If the object has a 'p' === 'me' (passed as arguments), it returns true (or false to discards the object)
return object[property] === value
})
}
console.log(filter(tree, "p", "me"))
CodePudding user response:
We can build this atop a reusable deep-filtering function, just passing it a predicate to say whether we're keeping an object. This one uses a deepFilter
function that I have lying around my virtual toolbox:
const deepFilter = (pred) => (xs) =>
xs .flatMap (({children = [], ...rest}, _, __, kids = deepFilter (pred) (children)) =>
pred (rest) || kids.length
? [{...rest, ...(kids.length ? {children: kids} : {})}]
: []
)
const keepProp = (name, value) =>
deepFilter (x => x [name] == value)
const tree= [{a: "1", children: [{a: "11", children: [{a: "111", p:"me"}, {a: "112"}]}, {a: "111", p: "me"}]}, {a: "2"}, {text: "3", p: "me"}]
console .log (keepProp ('p', 'me') (tree))
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that no objects are harmed in the use of this function. It treats your data as immutable.