I have a class called TreeNode
class TreeNode {
constructor(name) {
// Name of the node visible to user. It is string
self.name = name;
// Children of the node. it is array of TreeNode
self.children = [];
// If this field is true, children of the Node are shown to the user
self.expanded = false;
// If this field is true, it means that the node matches the current search and it is emphasized
self.matched = false;
}
The task is to perform the following: /* This function returns a new subtree of the original tree which satisfies the following requirements:
Function doesn't modify the original tree
The 'Node matches the searched' term means that Node's name contains the 'search' as a substring (case insensitive)
Node is included in the resulting subtree if Node, one of its ancestors, or one of its descendants matches the search
If Node matches the search, its matched property must be set to true, otherwise false
If at least one descendant of the Node matches the search, Node's expanded property must be set to true, otherwise false
@returns TreeNode | null */
makeTreeForSearchQuery(search) { // Do Something here return null; } }
I have a function within the class
makeTreeForSearchQuery(search)
{
if (self.children != null)
{
for(var i=0; i < self.children.length; i++)
{
self.children[i]= makeTreeForSearchQuery(search);
if(children.matched[i] == true)
{
//self.parent = children.matched[i];
//self.expanded = true;
}
//Something needs to be done here
}
}
if(self.name === search)
{
self.matched = true;
console.log(self.name);
}
return TreeNode;
}
I need to get this result: Search = 'two'
Result tree:
root - matched:false, expanded:true
left - matched:false, expanded:true
two - matched:true, expanded:false
Example
* Original tree
* root
* | \
* left right
* | | \ \
* one two three four
*
* Search = 'two'
Result tree:
* root - matched:false, expanded:true
* |
* left - matched:false, expanded:true
* |
* two - matched:true, expanded:false
Or if we describe it in JSON format
Original tree
{
name: "root",
expanded: false,
matched: false,
children: [
{
name: "left",
expanded: false,
matched: false,
children: [
{
name: "one",
expanded: false,
matched: false,
children: [],
},
{
name: "two",
expanded: false,
matched: false,
children: [],
},
],
},
{
name: "right",
expanded: false,
matched: false,
children: [
{
name: "three",
expanded: false,
matched: false,
children: [],
},
{
name: "four",
expanded: false,
matched: false,
children: [],
},
],
},
],
};
Result Tree:
{
name: "root",
expanded: true,
matched: false,
children: [
{
name: "left",
expanded: true,
matched: false,
children: [
{
name: "two",
expanded: false,
matched: true,
children: [],
},
],
},
],
}
I'm not sure what you (or your instructor) is looking for exactly, but we can do this in a more functional manner, without constructor functions or methods, with code something like this:
But the techniques may be beyond what you're supposed to be using for your course.
The factory function
treeNodeconstructs a plain JSON object, in a similar manner to your constructor function (once you fix theself/thisproblem.)matchtakes a query parameter and returns a function which takes your node, destructures it intonameandchildrenproperties (we can safely ignore the others for now), aliasingkidsforchildren, adds two blank parameters for technical reasons1 and then create achildrenparameter by recurring on the node's children, and filtering to include only those that are themselvesmatchedor which havematcheddescendants (and are thereforeexpanded.) We return a new object with the existingnameproperty, the new list ofchildren, andexpandedflag settrueif we have any children, and amatchedflag if the current name matches the query parameter.The base case for our recursion is slightly difficult to see. It happens when
childrenis empty; at that point, we don't make deeper calls tomatch. And our recursive case is simplykids .map (match (query)).We can certainly convert this to to something more OO, as needed. But I think this is simpler.
Update
I went ahead and tried an OO solution. It may seem more familiar to you.
Update 2
What Bergi mentioned in the comments is that I'm using a fairly obscure, and in some ways horrible, hack to squeeze an extra value into the parameters so that I can code with pure expressions, rather than statements. (The reasons for that involve a long discussion.)
But if you want, this version may seem more familiar:
It has the exact same behavior as my first sample.
Update 3
And now that I've mentioned that version, it probably makes sense to describe the other two versions I offered in the comments. One, using a really simple
callhelper,which we might write in either of two ways:
or
The second replaces that
callfunction with an IIFE. And again, we can write it in either of two ways:or
Any of these version would do the same thing, and they all help with my boycott of statements. I'm partial to the first
callversion in my own work, but don't tend to use it in answers on SO because there is often confusion about the simplecallfunction, confusion which distracts from the main points of the answers.I do use the IIFE version, but the syntax can be distracting.
1This is so that we can pass the
match(query)function tomap, which suppliesindexandarrayparameters we don't need, but still default the additionalchildrenparameter.