Skip to content

Instantly share code, notes, and snippets.

@bmhaskar
Last active May 10, 2019 17:36
Show Gist options
  • Save bmhaskar/5c48e89d5b43dbc89d794dbbfb66e2c9 to your computer and use it in GitHub Desktop.
Save bmhaskar/5c48e89d5b43dbc89d794dbbfb66e2c9 to your computer and use it in GitHub Desktop.
const next = (function(){
let a = 1;
return function(){
return a++;
}
})();
class TreeNode {
constructor(data, parent) {
this.data = data;
this.children = {};
this.key = next();
this.parent = parent;
}
add(data){
const newNode = new TreeNode(data, this);
this.children[newNode.key] = newNode;
}
findChildren(data, func) {
const children = Object.values(this.children);
if(this.data == data || (func && func(this))) {
return [this];
} else if(children.length) {
const foundChildren = children.reduce((prev,child) => prev.concat(child.findChildren(data, func)), [] ).filter(Boolean);
return foundChildren.length ? foundChildren: false;
}
return false;
}
findParent(data, func) {
if(this.parent) {
return this.parent.data == data || (func &&func(this)) ? this.parent : this.parent.findParent(data, func);
}
return false;
}
findParents(filterStr, func =false) {
const filter = new RegExp(filterStr)
if(this.parent) {
if((this.parent.data && filter.test( this.parent.data) )
|| (func && func(this.parent))) {
return [this.parent].concat(this.parent.findParents(filterStr, func)).filter(Boolean);
}
return this.parent.findParents(filterStr, func);
}
}
//default Bottom-up visit
visitChild(func, topDown) {
const children = Object.values(this.children);
if(children.length)
{
children.forEach(child => {
topDown && func(child);
child.visitChild(func, topDown);
})
}
!topDown && func(this);
}
}
class Tree {
constructor(data) {
this.root = new TreeNode(data);
}
findNodes (data, func) {
return this.root.findChildren(data,func );
}
add(data) {
return this.root.add(data);
}
remove(node) {
const parent = node.parent;
delete parent.children[node.key];
}
visit(func, topDown) {
topDown && func(root)
this.root.visitChild(func,topDown);
}
}
// Test use cases
// Create Tree
const tree = new Tree("root");
//Find "root" node
const root = tree.findNodes("root")[0];
//Add first level
root.add("r1c1");
root.add("r1c2");
root.add("r1c3");
const r1c1 = tree.findNodes("r1c1")[0]
//Add second order leaf
r1c1.add("r2c1");
const r2c1 = tree.findNodes("r2c1")[0]
//Add third order leaf
r2c1.add("r3c1");
//Find third order leaf
const r3c1 = tree.findNodes("r3c1")[0]
// Find node parent
const findParentResult = r3c1.findParent("r1c1")
const findParentResultWithCustomFunction = r3c1.findParent(null, (node) => node.parent.data == "r1c1")
console.log(findParentResult === findParentResultWithCustomFunction)
// Find node parents
const findParentsResult = r3c1.findParents("c")[0]
const findParentsResultWithCustomFunction = r3c1.findParents(null, (node) => new RegExp("c").test(node.data))[0]
console.log(findParentsResult == findParentsResultWithCustomFunction)
// Custom filter to find nodes
const customFilter = node1 => { return node1.key == 6 }
const cf = tree.findNodes(null, customFilter)[0]
console.log(cf==r3c1)
// Tree visitor depth first
tree.visit((child) => {
console.log(child)
})
// Tree visitor top down
const depthFirst = false;
tree.visit((child) => {
console.log(child)
}, depthFirst)
/**
*
true findParentResult === findParentResultWit...100:0
true findParentsResult == findParentsResultWi..105:0
true cf == r3c1 109:0
TreeNode { data: 'r3c1', 
children: [], 
key: 6, 
parent:  
TreeNode { data: 'r2c1', 
children: [ [Circular] ], 
key: 5, 
parent: TreeNode { data: 'r1c1', children: [Object], key: 2, parent: [Object] } } } 
at 112:4
TreeNode { data: 'r2c1', 
children: [ TreeNode { data: 'r3c1', children: [], key: 6, parent: [Circular] } ], 
key: 5, 
parent:  
TreeNode { data: 'r1c1', 
children: [ [Circular] ], 
key: 2, 
parent: TreeNode { data: 'root', children: [Object], key: 1, parent: undefined } } } 
at 112:4
TreeNode { data: 'r1c1', 
children: [ TreeNode { data: 'r2c1', children: [Object], key: 5, parent: [Circular] } ], 
key: 2, 
parent:  
TreeNode { data: 'root', 
children: [ [Circular], [Object], [Object] ], 
key: 1, 
parent: undefined } } 
at 112:4
TreeNode { data: 'r1c2', 
children: [], 
key: 3, 
parent:  
TreeNode { data: 'root', 
children: [ [Object], [Circular], [Object] ], 
key: 1, 
parent: undefined } } 
at 112:4
TreeNode { data: 'r1c3', 
children: [], 
key: 4, 
parent:  
TreeNode { data: 'root', 
children: [ [Object], [Object], [Circular] ], 
key: 1, 
parent: undefined } } 
at 112:4
TreeNode { data: 'root', 
children:  
[ TreeNode { data: 'r1c1', children: [Object], key: 2, parent: [Circular] }, 
TreeNode { data: 'r1c2', children: [], key: 3, parent: [Circular] }, 
TreeNode { data: 'r1c3', children: [], key: 4, parent: [Circular] } ], 
key: 1, 
parent: undefined } 
at 112:4
TreeNode { data: 'r3c1', 
children: [], 
key: 6, 
parent:  
TreeNode { data: 'r2c1', 
children: [ [Circular] ], 
key: 5, 
parent: TreeNode { data: 'r1c1', children: [Object], key: 2, parent: [Object] } } } 
at 117:4
TreeNode { data: 'r2c1', 
children: [ TreeNode { data: 'r3c1', children: [], key: 6, parent: [Circular] } ], 
key: 5, 
parent:  
TreeNode { data: 'r1c1', 
children: [ [Circular] ], 
key: 2, 
parent: TreeNode { data: 'root', children: [Object], key: 1, parent: undefined } } } 
at 117:4
TreeNode { data: 'r1c1', 
children: [ TreeNode { data: 'r2c1', children: [Object], key: 5, parent: [Circular] } ], 
key: 2, 
parent:  
TreeNode { data: 'root', 
children: [ [Circular], [Object], [Object] ], 
key: 1, 
parent: undefined } } 
at 117:4
TreeNode { data: 'r1c2', 
children: [], 
key: 3, 
parent:  
TreeNode { data: 'root', 
children: [ [Object], [Circular], [Object] ], 
key: 1, 
parent: undefined } } 
at 117:4
TreeNode { data: 'r1c3', 
children: [], 
key: 4, 
parent:  
TreeNode { data: 'root', 
children: [ [Object], [Object], [Circular] ], 
key: 1, 
parent: undefined } } 
at :117:4
TreeNode { data: 'root', 
children:  
[ TreeNode { data: 'r1c1', children: [Object], key: 2, parent: [Circular] }, 
TreeNode { data: 'r1c2', children: [], key: 3, parent: [Circular] }, 
TreeNode { data: 'r1c3', children: [], key: 4, parent: [Circular] } ], 
key: 1, 
parent: undefined } 
at 117:4
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment