Javascript Recursion inside class method (this behaviour) - javascript

The problem lies inside toString function , this does not actualize the scope as the function calls itself:
I need something to solve the problem , 'this' is the worst in javascript , i have implemented the exact data structure and function in python and it works... , i've tried binding and arrow functions , maybe you can help me out...
The expected result for the code down below :
1
|__2
|__3
|__4
|__5
class Node {
constructor(data){
this.data = data;
this.parent = null;
this.children = [];
Node.nodes.push(this);
this.index = Node.nodes.length;
}
addChild(node){
node.parent = this;
this.children.push(node);
}
getLevel(){
let level = 0;
while(this.parent){
level+=1;
this.parent = this.parent.parent;
}
//console.log('lvl',level);
return level;
}
toString (){
// console.log('lvl',this.getLevel());
let prefix = " ".repeat(this.getLevel()*3);
prefix += this.getLevel()===0 ? "" :"|__";
console.log(prefix + this.index);
if(this.children){
for(let i = 0; i < this.children.length; i++){
this.children[i].toString();
}
}
}
pathToRoot(){
return 0;
}
}
Node.nodes = [];
const main = (()=>{
let root = new Node('root');
let kid1 = new Node('kid1');
let kid2 = new Node('kid2');
let kid3 = new Node('kid3');
let kid4 = new Node('kid4');
root.addChild(kid1);
kid1.addChild(kid2);
kid2.addChild(kid3);
kid3.addChild(kid4);
console.log('kid4 lvl :',kid4.getLevel())
root.toString(root);
})()

You assign the parent of the parent in a loop. Instead use a variable for looping the parents.
class Node {
constructor(data) {
this.data = data;
this.parent = null;
this.children = [];
if (!Node.nodes) Node.nodes = [];
Node.nodes.push(this);
this.index = Node.nodes.length;
}
addChild(node) {
node.parent = this;
this.children.push(node);
}
getLevel() {
let level = 0;
let parent = this.parent; // start with parent
while (parent) { // check value
level += 1;
parent = parent.parent; // assign parent
}
//console.log('lvl',level);
return level;
}
toString() {
// console.log('lvl',this.getLevel());
let prefix = " ".repeat(this.getLevel() * 3);
prefix += this.getLevel() === 0 ? "" : "|__";
console.log(prefix + this.index);
if (this.children) {
for (let i = 0; i < this.children.length; i++) {
this.children[i].toString();
}
}
}
pathToRoot() {
return 0;
}
}
const main = (() => {
let root = new Node('root');
let kid1 = new Node('kid1');
let kid2 = new Node('kid2');
let kid3 = new Node('kid3');
let kid4 = new Node('kid4');
root.addChild(kid1);
kid1.addChild(kid2);
kid2.addChild(kid3);
kid3.addChild(kid4);
console.log('kid4 lvl :', kid4.getLevel())
root.toString(root);
console.log(root);
})();
.as-console-wrapper { max-height: 100% !important; top: 0; }

It seems like it is not about the this mechanism. You lack a base case(so the recursive function will keep running forever). You need to think of in what situation the recursion should end.
toString (){
// think of your base case here. Examples are as below
// should it be prefix === ""?
// should it be when length of prefix smaller or greater than specific length
let prefix = " ".repeat(this.getLevel()*3);
prefix += this.getLevel()===0 ? "" :"|__";
console.log(prefix + this.index);
if(this.children){
for(let i = 0; i < this.children.length; i++){
this.children[i].toString();
}
}
}

Related

problem using .split() method in a function but it works on console.log

the problem is only in the bottom function objectPutter
specifically the line with wowza.split(' '); labelled with the comment
let eq
let x = null
let bracketNum = 0
let k = 0
let pre = 0
class subEqCreator { //subEq object
constructor() {
this.precede = 0;
this.text = '';
}
parser() {
this.text += eq[k]
}
ma() {
this.text.split(' ')
}
};
function trigger() { //used for HTML onClick method
show();
brackets();
subEqDynamic()
parseEquation();
objectPutter()
};
function show() {
const recent = document.querySelector("ol");
const txt = document.getElementById('input');
eq = txt.value;
li = document.createElement('li');
li.innerText = eq;
recent.appendChild(li);
txt.value = '';
};
function brackets() { //counts how many brackets appear
for (let i = 0; i < eq.length; i++) {
if (eq[i] == "(") {
bracketNum++;
};
};
};
let subEqDynamic = function() { // creates a new object for each bracket
for (let count = 0; count <= bracketNum; count++) {
this['subEq' + count] = x = new subEqCreator()
};
};
function parseEquation() { // assign characters to SubEq object
let nextIndex = 0;
let currentIndex = 0;
let lastIndex = [0];
let eqLen = eq.length;
let nex = this['subEq' + nextIndex]
for (k; k < eqLen; k++) {
if (eq[k] == "(") {
nextIndex++;
pre++
this['subEq' + currentIndex].text += '( )';
this['subEq' + nextIndex].precede = pre;
lastIndex.push(currentIndex);
currentIndex = nextIndex;
} else if (eq[k] == ")") {
pre--
currentIndex = lastIndex.pop();
} else {
this['subEq' + currentIndex].parser()
}
}
}
function objectPutter() {
for (let i = 0; i < bracketNum; i++) {
let wowza = this['subEq' + i].text
wowza.split(' '); // 🚩 why isnt it working here
console.log(subEq0);
for (let j = 1; j <= wowza.length; j += 2) { // for loop generates only odds
let ni = i++
wowza.splice(j, 0, this['subEq' + ni])
console.log(i)
}
}
}
to fix this i tried;
making a method for it ma() in the constructor.
putting in the function parseEquation above in case it was a scope issue.
also, i noticed subEq0.split(' ') worked in browser console even replicating it to the way i done it using this['subEq' + i].text.split(' ') where i = 0.
After it runs the it says .splice is not a function and console.log(subEq0) shows subEq0.text is still a string
.split() does not change the variable it returns the splitted variable

Trouble finding the height of my first NON Binary Tree in JS

Here is the constructor function as well as the 'add' method...
function Tree(value) {
this.value = value;
this.children = [];
}
Tree.prototype.add = function(...value) {
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
let node = new Tree;
node.value = value[i];
this.children[this.children.length] = node;
}
return;
}
let node = new Tree;
node.value = value;
this.children[this.children.length] = node;
};
Here is the 'height' method I am working on...
Tree.prototype.height = function() {
let height = 0;
if (this.children != null) {
if (this.children.length == 0) {
return height;
} else {
for (let i = 0; i < this.children.length; i++) {
height = Math.max(height, this.height(this.children[i]));
}
return depth + 1;
}
return height;
}
};
I am unsure of why I am getting "RangeError: Maximum call stack size exceeded" because the method should return height if the children array length is 0.
Here are the test cases I am using...
tree = new Tree();
tree.add(5);
tree.add(8);
var son = tree.children[0];
son.add(1);
son.add(4);
var daughter = tree.children[0];
daughter.add(10);
var grandson = son.children[1];
grandson.add(3);
grandson.height() //should return 1
tree.height() //should return
Any tips on how to fix my infinite loop will be greatly appreciated. Thank you for your time!

given an array representing a hierachy, output data into a tree form in JS

Given a data file which has an array representing a hierarchy. Create a tree data structure by writing a script in Javascript. Output the data in tree form:
Data file:
["transportation.cars.Mazda",
"transportation.cars.Honda",
"transportation.cars.Toyota",
"transportation.train.lightRail",
"transportation.train.rapidTransit",
"transportation.waterVehicle.ferry",
"transportation.waterVehicle.boats"
...]
Output in tree form:
root
transportation
cars
Mazda
Honda
Toyota
train
lightRail
rapidTransit
waterVehicle
ferry
boats
My attempt:
var root = new Node('root');
var arr = ["transportation.cars.Mazda",
"transportation.cars.Honda",
"transportation.cars.Toyota",
"transportation.train.lightRail",
"transportation.train.rapidTransit",
"transportation.waterVehicle.ferry",
"transportation.waterVehicle.boats"
]
for(var i of arr){
var res=i.split(".");
root.addChild(new Node(res[0]));
res[0].addChild(new Node(res[1]));
res[1].addChild(new Node(res[2]));
}
this.addChild = function(node) {
node.setParentNode(this);
this.children[this.children.length] = node;
}
console.log(root);
I am trying to create a tree structure using JavaScript, but it does not has the same function as in Java (i.e. it does not have class method unless using Typescript. )
You can use something similar to a trie tree. The way you add a node would have to be much more specific. But it's possible with something like this.
function Node(word)
{
this.value = word;
this.children = {};
}
function AddDotChain(chain)
{
let arr = chain.split('.');
let currentNode = this;
function recurse(currentIndex)
{
if(currentIndex === arr.length)
{
return;
}
let currentWord = arr[currentIndex];
if(currentNode.children[currentWord])
{
currentNode = currentNode[currentWord];
return recurse(currentIndex + 1);
}
let child = new Node(currentWord);
currentNode.children[currentWord] = child;
currentNode = child;
return recurse(currentIndex + 1);
}
}
Where you just slap the entire chain in there without splitting it. There's probably a flaw in my logic somewhere but the overall idea should work. This can also be done iteritavely if you wanna reduce the overhead of recursion. Forgive the messiness, Tried to type this as fast as possible.
Here's a sloppy sloppy implementation on repl.it.
You can do it, with a data structure as Tree, you only need loop over the array of string that contains the data and split them by dot and then add each item to the tree instance that will be created when you execute the function that take your array and output as a Tree data structure.
this code can help you
var arr = ["transportation.cars.Mazda",
"transportation.cars.Honda",
"transportation.cars.Toyota",
"transportation.train.lightRail",
"transportation.train.rapidTransit",
"transportation.waterVehicle.ferry",
"transportation.waterVehicle.boats"
];
function Node(data) {
this.data = data;
this.children = [];
}
function Tree(data) {
this.root = null;
}
Tree.prototype.contains = function(data) {
return this.find(data) ? true : false;
}
Tree.prototype.add = function(data, node) {
const newNode = new Node(data);
if (!this.root) {
this.root = newNode;
return;
}
const parent = node ? this.find(node) : null;
if (parent) {
if (!this.contains(data)) {
parent.children.push(newNode);
}
}
}
Tree.prototype.find = function(data) {
if (this.root) {
const queue = [this.root];
while(queue.length) {
const node = queue.shift();
if (node && node.data === data) {
return node;
}
for(var i = 0; i < node.children.length; i++) {
const child = node.children[i];
queue.push(child);
}
}
}
return null;
}
function createTreeOfTransportation(arr) {
const tree = new Tree();
for(var i = 0; i < arr.length; i++) {
const element = arr[i];
const nodes = element.split('.');
for (var j = 0; j < nodes.length; j++) {
const currentNode = nodes[j];
const parent = nodes[j-1];
console.log(j, parent);
tree.add(currentNode, parent);
}
}
return tree;
}
console.log(createTreeOfTransportation(arr));

Improve the performance of recursion for generating tree using JSON data

I need to construct a tree structure from data represented in JSON as object and parent relationship. I have implemented below code which is successfully doing the job but I am not sure whether it's giving the best performance (I mean doing the job in as less as possible iteration).
Please Note, the root of the tree is represented as parent is same as object. e.g. {"object":"A", "parent":"A"}
Suggestions about any other implementation with better performance would be helpful!!
var jsonInput =
[
{"object":"A", "parent":"A"},
{"object":"B", "parent":"A"},
{"object":"C", "parent":"A"},
{"object":"D", "parent":"B"},
{"object":"E", "parent":"B"},
{"object":"F", "parent":"D"},
{"object":"G", "parent":"D"},
{"object":"H", "parent":"E"},
{"object":"I", "parent":"E"},
{"object":"J", "parent":"C"},
{"object":"K", "parent":"C"},
{"object":"L", "parent":"J"},
{"object":"M", "parent":"J"},
{"object":"N", "parent":"K"},
{"object":"O", "parent":"K"},
{"object":"P", "parent":"N"},
{"object":"Q", "parent":"N"},
{"object":"R", "parent":"O"},
{"object":"S", "parent":"O"}
];
var root = getRoot();
root.childs = findChildrens(root);
console.log("The tree hierarchy is:")
console.log(root);
function getRoot() {
var root;
for (var counter = 0; counter < jsonInput.length; counter++){
var item = jsonInput[counter];
if(item.object === item.parent) {
root = item;
break;
}
}
var returnValue = JSON.parse(JSON.stringify(root));
root.visited = true;
return returnValue;
}
function findChildrens(parentObject) {
var childs = [];
for (var counter = 0; counter < jsonInput.length; counter++){
var item = jsonInput[counter];
if(item.parent === parentObject.object && !item.visited) {
var child = JSON.parse(JSON.stringify(item));
item.visited = true;
child.childs = findChildrens(child);
childs.push(child);
}
}
return childs;
}
A simpler solution with a linear runtime.
var data = [
{"object":"A", "parent":"A"},
{"object":"B", "parent":"A"},
{"object":"C", "parent":"A"},
{"object":"D", "parent":"B"},
{"object":"E", "parent":"B"},
{"object":"F", "parent":"D"},
{"object":"G", "parent":"D"},
{"object":"H", "parent":"E"},
{"object":"I", "parent":"E"},
{"object":"J", "parent":"C"},
{"object":"K", "parent":"C"},
{"object":"L", "parent":"J"},
{"object":"M", "parent":"J"},
{"object":"N", "parent":"K"},
{"object":"O", "parent":"K"},
{"object":"P", "parent":"N"},
{"object":"Q", "parent":"N"},
{"object":"R", "parent":"O"},
{"object":"S", "parent":"O"}
];
var rootNodes = data.filter(function(node) {
if (node.object in this)
throw new Error("duplicate object " + node.object);
this[node.object] = node;
node.children = [];
if (node.parent === node.object) return true;
var parent = this[node.parent];
if (!parent)
throw new Error("invalid parent " + node.parent);
parent.children.push(node);
}, Object.create(null));
console.log(rootNodes);
.as-console-wrapper {
top: 0;
max-height: 100%!important
}

JavaScript updating last index class data

I have following issue.
I have array of objects, and when I want to get one of the items and update data, it updates last data.
for example:
var arr = [];
for (var i = 0; i < 8; i++){
var c = new MyClass1(i);
arr.push (c)
}
and the MyClass1
(function () {
var score = 0;
function MyClass1(id){
this.id = id;
this.x = 100;
//some code. not important
}
var p = MyClass1.prototype;
p.updateScore = function (s){
score = s;
}
window.MyClass1 = MyClass1;
}());
and function which returns one of these classes
var getMyClassesById = function(/* int */ id){
var size = arr.length;
for (var i = 0; i<size; i++){
if (id == arr[i].id){
return arr [i];
}
}
}
Finally I'm calling function and want to update Score
getMyClassesById(1).updateScore (122);
it's updates last index item Score, and calls last item "updateScore" function... why?
but when i'm changing some other property its changes correctly for example "x". I can't understand is here something not right with prototypes?
Your variable score is not defined as a member of MyClass - it is only defined in the scope of your closure. Your code will work, but there will only be 1 "score" for all instances of MyClass.
If score is supposed to be part of MyClass then move it
function MyClass1(id){
this.id = id;
this.x = 100;
this.score = 0
//some code. not important
}
And update the method:
var p = MyClass1.prototype;
p.updateScore = function (s){
this.score = s;
}
(function () {
function MyClass1(id){
this.id = id;
this.x = 100;
this.score = 0;
//some code. not important
}
var p = MyClass1.prototype;
p.updateScore = function (s){
this.score = s;
}
window.MyClass1 = MyClass1;
}());
var arr = [];
for (var i = 0; i < 8; i++){
var c = new MyClass1(i);
arr.push (c)
}
var getMyClassesById = function(/* int */ id){
var size = arr.length;
for (var i = 0; i<size; i++){
if (id == arr[i].id){
return arr [i];
}
}
}
getMyClassesById(1).updateScore (122);
console.log(arr);

Categories

Resources