DepthFirstInOrer in JS - test code fail to print the value - javascript

I've created a method to traverse Depth first in order with a recursion in my BinaryTree class.
I don't understand where to add this.value for the value of my left child and right child to be received in my test code as expected. I've tried every possible place but without success. when I use console.log to debug, i can only manage to get the value or [Function (anonymous)]
Method:
traverseDepthFirstInOrder(fn) {
//handle left child (if exists)
if (this.left) {
this.left.traverseDepthFirstInOrder(fn);
}
//handle right child (if exists)
if (this.right) {
this.right.traverseDepthFirstInOrder(fn);
}
}
testCode:
test("should call the fn on left nodes, center nodes, then right nodes", () => {
let test = [];
binaryTree.add(4);
binaryTree.add(14);
binaryTree.add(6);
binaryTree.add(16);
binaryTree.add(2);
binaryTree.add(12);
binaryTree.traverseDepthFirstInOrder(e => test.push(e.value));
expect(test).toEqual([2, 4, 6, 10, 12, 14, 16]);
});
terminal failed:
Expected - 9
Received + 1

This was what was meant in trincot's comment. This is supposed to traverse the tree in an inorder manner, calling the supplied function on every node. But you don't call the function. You're missing one line:
class Tree {
constructor (value, left = null, right = null) {this.value = value; this .left = left; this .right = right}
traverseDepthFirstInOrder (fn) {
//handle left child (if exists)
if (this.left) {
this.left.traverseDepthFirstInOrder(fn);
}
// handle the root node
fn (this) // *** This line was missing ***
//handle right child (if exists)
if (this.right) {
this.right.traverseDepthFirstInOrder(fn);
}
}
}
const binaryTree = new Tree (10, new Tree (4, new Tree (2), new Tree (6)), new Tree (14, new Tree (12), new Tree (16)))
let test = [];
binaryTree.traverseDepthFirstInOrder(e => test.push(e.value));
console .log (test)
Ignore the constructor and my method of creating the tree; I don't have the rest of the class you're using. But this change should fix your version as well.

Related

How to modify tree object by property?

I have an object with type:
export interface TreeNode extends ITreeNode {
name: string,
children: TreeNode[],
show?: boolean;
}
I need to reduce this object by property show and return a new tree where show is true or undefined.
I have tried this:
function prepareNodes(source: TreeNode) {
if (source.show!== undefined || source.show == false) delete source;
if (source.children) {
source.children.forEach((child: TreeNode) => {
this.prepareNodes(child);
});
}
}
Also I tried:
function prepareNodes(source: any) {
if (source.show !== undefined && source.show === false) source = null;
if (source.children) {
source.children = source.children.filter((child: any) => child.show== undefined || child.show === true);
source.children.forEach((child: any) => prepareNodes(child));
}
}
Currently my assumption is that you want to produce a new tree containing just those nodes of the original tree where the show property is either true or undefined for that node and all ancestor nodes. So if show is false on any node, the output tree will not contain that node or any subtree of that node.
I also assume that it's possible for the root node to have show of false, in which case the whole tree might end up undefined. You can't set modify an object to become undefined; you can change its contents, but you can't delete it. So I'm not going to present anything that tries to modify the original tree. I won't touch the original tree. Instead I will produce a completely new tree.
Here goes:
const defined = <T,>(x: T | undefined): x is T => typeof x !== "undefined";
function filterTree(source: TreeNode): TreeNode | undefined {
if (source.show === false) return;
return {
name: source.name,
show: source.show,
children: source.children.map(filterTree).filter(defined)
}
}
The filterTree() function will return undefined if the argument node's show property is exactly false (and not undefined). Otherwise, it produces a new node with the same name and show, and whose children property is what you get when you call filterTree() (recursively) on each of the original node's children, and then filter out any undefined nodes.
I'm using a user-defined type guard function called defined to let the compiler know that the filtering takes an array of TreeNode | undefined and produces an array of TreeNode, eliminating any undefined entries.
Hopefully this meets your use cases; please test it out on whatever data you have and check, because the question unfortunately did not include such data.
Playground link to code

React-Native - recursing through nested object crashing

I have the following function taken from (Iterate through Nested JavaScript Objects) implemented in a plain CRNA project:
var findObjectByLabel = function(obj, label) {
if(obj.label === label) { return obj; }
for(var i in obj) {
if(obj.hasOwnProperty(i)){
var foundLabel = findObjectByLabel(obj[i], label);
if(foundLabel) { return foundLabel; }
}
}
return null;
};
When i try to execute this code in the constructor or any lifecycle method, the app crashes with Maximum Call Stack Size exceeded. Is this something that is not allowed in RN? Will I have to convert this into an iterative version?
If you consider the following scenario for your above function, you can see why it is breaking:
type Node = { link: Node; value: number; };
const x: Node = { link: null, value: 0 };
const y: Node = { link: x, value: 1 };
x.link = y;
findObjectByLabel(x, 'foo');
Because there is a circular reference, your recursion is going to go on infinitely and you will hit the max call stack size.
It is likely that there is some sort of circular reference within your object structure that is running you up against this problem.
If you can guarantee that all hit objects will have a non-null label and that labels are unique you could keep track of seenLabels and not recursive into an object that you've already seen the label of.

walking a tree with Promises

I have a tree structure that I want to walk using Promises, and I haven't figured out the right code pattern for it.
Assume that we're given node names, and the act of converting a node name to a node is an asynchronous process (e.g. involves a web access). Also assume that each node contains a (possibly empty) list of children names:
function getNodeAsync(node_name) {
// returns a Promise that produces a node
}
function childrenNamesOf(node) {
// returns a list of child node names
}
What I want to end up with a method with this signature:
function walkTree(root_name, visit_fn) {
// call visit_fn(root_node), then call walkTree() on each of the
// childrenNamesOf(root_node), returning a Promise that is fulfilled
// after the root_node and all of its children have been visited.
}
that returns a Promise that's fulfilled after the root node and all of its children have been visited, so it might be called as follows:
walkTree("grandpa", function(node) { console.log("visiting " + node.name); })
.then(function(nodes) { console.log("found " + nodes.length + " nodes.")});
update
I've create a gist that shows my first attempt. My (slightly buggy) implementation for walkTree() is:
function walkTree(node_name, visit_fn) {
return getNodeAsync(node_name)
.then(function(node) {
visit_fn(node);
var child_names = childrenNamesOf(node);
var promises = child_names.map(function(child_name) {
walkTree(child_name, visit_fn);
});
return Promise.all(promises);
});
};
This visits the nodes in the correct order, but the outermost Promise resolves before all the sub-nodes have been visited. See the gist for full details.
And as #MinusFour points out, using this technique to flatten the list of nodes is rather pointless. In fact, I really just want the final promise to fire when all the nodes have been visited, so a more realistic use case is:
walkTree("grandpa", function(node) { console.log("visiting " + node.name); })
.then(function() { console.log("finished walking the tree")});
Well it isn't much of a problem to handle a function call for each node, but gathering the node values is kind of a problem. Kind of hard to walk that tree, your best bet would be to map it to a tree with no eventual values. You could use something like:
function buildTree(root_name) {
var prom = getNodeAsync(root_name);
return Promise.all([prom, prom.then(function(n){
return Promise.all(childrenNamesOf(n).map(child => buildTree(child)))
})]);
}
From there on you do:
var flatTree = buildTree(root_name).then(flatArray);
flatTree.then(nodes => nodes.forEach(visit_fn));
flatTree.then(nodes => whateverYouWantToDoWithNodes);
To flatten the array you could use:
function flatArray(nodes){
if(Array.isArray(nodes) && nodes.length){
return nodes.reduce(function(n, a){
return flatArray(n).concat(flatArray(a));
});
} else {
return Array.isArray(nodes) ? nodes : [nodes];
}
}
To be honest, it's pointless to have the tree walker if you want a list of nodes you are better up flattening it up and then iterating the elements, but you can walk the array tree if you want.
Despite what I said in the O.P, I don't really care about the return values of the final promise, but I do want to wait until all the nodes have been traversed.
The problem with the original attempt was simply a missing return statement in the map() function. (Despite appearances, this is essentially structurally identical to #MinusFour's answer.) Corrected form below:
function walkTree(node_name, visit_fn) {
return getNodeAsync(node_name)
.then(function(node) {
visit_fn(node);
var child_names = childrenNamesOf(node);
var promises = child_names.map(function(child_name) {
return walkTree(child_name, visit_fn);
});
return Promise.all(promises);
});
};
Here are two use cases for walkTree(). The first simply prints the nodes in order then announces when the tree walk is finished:
walkTree("grandpa", function(node) { console.log("visiting " + node.name); })
.then(function() { console.log("finished walking the tree")});
The second creates a flat list of nodes, made available when the tree walk completes:
var nodes = [];
walkTree("grandpa", function(node) { nodes.push(node) })
.then(function() { console.log('found', nodes.length, 'nodes);
console.log('nodes = ', nodes); });

GoJS delete child nodes without knowing parent node's key

I have a goJS diagram with a custom model. When dropping a node on another node, I link them when the mouseDrop fires and set the from and to in the link data on the diagram.model:
mydiagram.model.addLinkData({ from: oldNodeModel.key, to: dragNodeModel.key });
This all works fine. In my node template I have a custom template which puts a panel around the nodes with a delete button. This delete button is simply an image with a click event.
Now when I click the delete image/button, I want to delete this now and all its child nodes.
My issue is I cannot find the children.
I have user events like findNodesOutOf, which yields no results and findNodesConnected which finds parents and child nodes and deletes the lot - which is not what I want.
Any idea how I can solve this?
You can get the item to delete by using the diagram.selection:
var nodeToDelete = mydiagram.selection.iterator.first();
Next to find all the children of this node I recommend a recursive function which will do the following:
Take in the node you want to delete,
Find all the connected nodes to it using mydiagram.getChildrenNodes(nodeToDelete)
Itterrate through the cconnected nodes
Check if each node is a child, by using the linkNodeModel and checking is the link goes from the currentnode to the child node.
Then call the recursive function again with this child node
The recursive function will return an array with all child nodes
Then you can delete them.
Your code will look something like this:
function deleteNode()
{
// TAKE NOTE - This will get all selections so you need to handel this
// If you have multiple select enabled
var nodeToDelete = mydiagram.selection.iterator.first();
var childNodes = getChildNodes(deletedItem);
//Remove linked children
$.each(childNodes, function()
{
myDiagram.remove(this);
});
// Then also delete the actual node after the children was deleted
// TAKE NOTE - This will delete all selections so you need to handle this
// If you have multiple select enabled
mydiagram.commandHandler.deleteSelection();
}
The recursive function keeps checking each node for its children and adds them to an aray:
function getChildNodes(deleteNode)
{
var children = [];
var allConnected= deleteNode.findNodesConnected();
while (allConnected.next())
{
var child = allConnected.value;
// Check to see if this node is a child:
if (isChildNode(deleteNode, child))
{
// add the current child
children.push(child);
// Now call the recursive function again with the current child
// to get its sub children
var subChildren = getChildrenNodes(child);
// add all the children to the children array
$.each(subChildren, function()
{
children.push(this);
});
}
}
// return the children array
return children;
}
This function will check if the node is a child by looking at the links in the diagram and checking to to and from against the current node and child node:
function isChildNode(currNode, currChild)
{
var links = myDiagram.links.iterator;
while (links.next())
{
// Here simply look at the link to determine the direction by checking the direction against the currNode and the child node. If from is the current node and to the child node
// then you know its a vhild
var currentLinkModel = links.value.data;
if (currentLinkModel.from === currNode.data.key && currentLinkModel.to === currChild.data.key)
{
return true;
}
}
return false;
}

XUL/Thunderbird: startEditing return

I'm playing with the thunderbird codebase, the aim being to implement inline contact editing. The current code catches the Click event on a XUL tree, and if it's a double click (events.detail == 2), it open the profile editor. I modified it so as to start editing the current treeCell, and I did add editable=true to the corresponding XUL document. The updated code reads
var orow = {}, ocolumn = {}, opart = {};
gAbResultsTree.treeBoxObject.getCellAt(event.clientX, event.clientY,
orow, ocolumn, opart);
var row = orow.value, column = ocolumn.value.index;
if (row == -1)
return;
if (event.detail == 2)
gAbResultsTree.startEditing(row, column);
Unfortunately, when the code reaches the startEditing part, it returns
Error: uncaught exception: [Exception... "Component returned failure code: 0x80004001 (NS_ERROR_NOT_IMPLEMENTED) [nsITreeView.isEditable]" nsresult: "0x80004001 (NS_ERROR_NOT_IMPLEMENTED)" location: "JS frame :: chrome://global/content/bindings/tree.xml :: startEditing :: line 337" data: no]
I'm pretty much lost here. Could someone with more XUL experience help?
Thanks!
I was trying to do something similar and I have same problem.
Wrapper with original abview set as __proto__ with functions overriden works fine until it is set as abResultsTree's view.
I've finally found (I hope) an elegant solution.
function MyAbView() {
this.originalAbViewInstance = this.originalAbViewFactory.createInstance(null, Ci.nsIAbView);
if (!this.proxiesGenerated) {
// find out which interfaces are implemented by original instance, their property proxies will be generated later
for (var ifName in Ci) {
if (Ci[ifName] instanceof Ci.nsIJSID && this.originalAbViewInstance instanceof Ci[ifName]) {
MyAbView.prototype.supportedInterfaces.push(Ci[ifName]);
}
}
function generatePropertyProxy(name) {
Object.defineProperty(MyAbView.prototype, name, {
get: function() {
return this.originalAbViewInstance[name];
},
set: function(val) {
this.originalAbViewInstance[name] = val;
},
enumerable: true
});
}
for (var prop in this.originalAbViewInstance) {
if (this[prop] == undefined) {
generatePropertyProxy(prop);
}
}
MyAbView.prototype.proxiesGenerated = true;
} else {
for each (var interface in this.supportedInterfaces) {
this.originalAbViewInstance.QueryInterface(interface);
}
}
}
MyAbView.prototype = {
classID: null,
_xpcom_factory: {
createInstance: function(outer, iid) {
return new MyAbView().QueryInterface(iid);
}
},
QueryInterface: function(aIID) {
for each (var interface in this.supportedInterfaces) {
if (interface.equals(aIID)) {
return this;
}
}
throw Components.results.NS_ERROR_NO_INTERFACE;
},
originalAbViewFactory: null,
originalAbViewInstance: null,
proxiesGenerated: false,
supportedInterfaces: [],
// any overriden functions come here
};
It's implemented as a component to replace the original abview, but it might be modified to just create a wrapper.
The <tree> widget uses an nsITreeView object to retrieve or manipulate data that needs to be displayed. There are predefined nsITreeView implementations reading data from the DOM or RDF datasources but one can choose to use his own tree view. Thunderbird's address book chooses the latter:
gAbView = Components.classes["#mozilla.org/addressbook/abview;1"]
.createInstance(Components.interfaces.nsIAbView);
...
gAbResultsTree.treeBoxObject.view =
gAbView.QueryInterface(Components.interfaces.nsITreeView);
Unfortunately for you, the component in question is implemented in C++, in the file nsAbView.cpp. This means that changing it without recompiling Thunderbird isn't possible. And the existing component doesn't implement isEditable() and setCellText() methods that would be required to edit tree cells.
If you don't want to mess with C++ yet, you could wrap that component in your own object. Something like this:
gAbView = Components.classes["#mozilla.org/addressbook/abview;1"]
.createInstance(Components.interfaces.nsIAbView);
gAbViewWrapper = {
__proto__: gAbView,
QueryInterface: function(iid)
{
gAbView.QueryInterface(iid);
return this;
},
isEditable: function(row, col)
{
// Do something here
},
setCellText: function(row, col, value)
{
// Do something here
}
};
...
gAbResultsTree.treeBoxObject.view =
gAbViewWrapper.QueryInterface(Components.interfaces.nsITreeView);
Method isEditable() should check again whether this particular cell is editable - even if the column is editable, individual cells don't have to be. And setCellText() should store the new value for the cell.

Categories

Resources