How to skip last operation in recursive function? - javascript

There is a recursive function like this:
How do I exclude the last iteration and dont get last node in tree?
export function getFullName(treeNode: TreeNode, fullname = ''): string {
if (treeNode.parent) {
if (fullname) fullname = `${treeNode.name}/${fullname}`;
else fullname = treeNode.name;
fullname = getFullName(treeNode.parent, fullname);
}
return fullname;
}

Actually the reason you use tree Structure most of time because you want to make use of the structure and make searching easily.
You can use while loop to check if parent node exist instead of recursive.
class TreeNode {
constructor(id, name, treeNode) {
this.id = id;
this.name = name;
this.parent = treeNode === undefined ? null : treeNode;
}
}
const node1 = new TreeNode(1, "node1");
const node2 = new TreeNode(2, "node2", node1);
const node3 = new TreeNode(2, "node3", node2);
function getFullName(treeNode) {
let node = treeNode;
let fullName = "";
while (node) {
fullName = `${node.name}/${fullName}`;
node = node.parent;
}
return fullName;
}
const output = getFullName(node3);
console.log(output);

Related

Problems when printing a circular singly linked list

I have a circular singly linked list code:
class Node{
constructor(value){
this.value = value;
this.next = null;
}
}
class LinkdeList{
constructor(){
this.first = null;
this.last = null;
}
empty(){
return this.first === null
}
insert(value){
let newest = new Node(value);
if (this.empty()) {
this.first = this.last = newest;
this.last.next = this.first;
}else{
newest.next = this.first;
this.first = newest;
this.last.next = this.first;
}
}
traverse(){
let aux = this.first;
while (aux.next != this.first) {
console.log(aux.value);
aux = aux.next;
}
}
}
let linked = new LinkdeList();
linked.insert("David");
linked.insert("John");
linked.insert("Adam")
linked.insert("Bob");
linked.traverse();
And when I tried to print the list, I just get in console 3 names:
Bob
Adam
John
And as you can see I push 4 names in my linked list. I tried to print the values of my list in the traverse method, but It didn´t work because I don´t get in console:
Bob
Adam
John
David
The loop stops one step too early. This is a good case for a do ... while loop. You should also protect it from failing when the list is empty
traverse() {
if (this.empty()) return; // <---
let aux = this.first;
do {
console.log(aux.value);
aux = aux.next;
} while (aux != this.first);
}
Some other remarks on your code:
As in a non-empty circular list it is always true that the head follows after the tail, it is actually not needed to maintain a first reference. Just keep a last reference, knowing that you can always get the head of the list via last.next.
console.log should not be used in a class method for anything else than debugging. Give your traverse method more flexibility by making it a generator. That way you leave the decision of what to do with the values to the caller of that method.
As in a circular list a node should never have a next property with a null value, don't assign null in the Node constructor. Instead give it a self-reference.
Name the empty method isEmpty as it more clearly indicates that this will not empty the list, but will return whether it is empty.
Fix a typo in the class name: LinkedList
class Node {
constructor(value) {
this.value = value;
this.next = this; // self-reference
}
}
class LinkedList {
constructor() {
this.last = null; // No need for a `first`
}
isEmpty() {
return this.last === null;
}
insert(value) {
const newest = new Node(value);
if (!this.isEmpty()) {
newest.next = this.last.next;
this.last.next = newest;
}
this.last = newest;
}
*traverse() { // Generator
if (this.isEmpty()) return; // Guard
let aux = this.last;
do {
aux = aux.next;
yield aux.value; // Don't print. Yield instead.
} while (aux != this.last);
}
}
const linked = new LinkedList();
linked.insert("David");
linked.insert("John");
linked.insert("Adam")
linked.insert("Bob");
// Caller of traverse can decide what to do: we want to print:
for (const name of linked.traverse()) console.log(name);
Your code works perfectly fine! You just need to tweak your traversal() method because the while loop breaks before it gets a chance to log the last node.
You can try something like this:
traverse(){
let aux = this.first;
while (true) {
console.log(aux.value);
aux = aux.next;
if (aux == this.first) {
break;
}
}
}
I will expand an attribute (count)
constructor() {
...
this.count = 0;
}
Calculate it when insert is called
insert(value) {
...
this.count = this.count + 1;
}
If there is an extension removal method later, remember to calculate it
remove() {
...
this.count = this.count - 1;
}
And adjust the conditional expression of traverse,
replace while (aux.next != this.first) with for (let i = this.count; i > 0; i--)
I prefer trincot's answer, my answer is aimed at a small scope of
code changes.
In practice I will design it with a similar structure(trincot's answer).
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkdeList {
constructor() {
this.count = 0;
this.first = null;
this.last = null;
}
empty() {
return this.first === null
}
insert(value) {
let newest = new Node(value);
if (this.empty()) {
this.first = this.last = newest;
this.last.next = this.first;
} else {
newest.next = this.first;
this.first = newest;
this.last.next = this.first;
}
this.count = this.count + 1;
}
traverse() {
let aux = this.first;
for (let i = this.count; i > 0; i--) {
console.log(aux.value);
aux = aux.next;
}
}
}
let linked = new LinkdeList();
linked.insert("David");
linked.insert("John");
linked.insert("Adam")
linked.insert("Bob");
linked.traverse();

Trying to return just the description in an array of instances of a class

So this is what I am trying to solve:
class ViewRole {
name
description
constructor(name, description) {
this.name = name;
this.description = description;
}
}
class NewRole {
name;
description;
constructor(name, description) {
this.name = name;
this.description = description;
}
}
var armadilloRoles = [
new NewRole('Billing', 'armadillo.organization.billing'),
new NewRole('Doctor', 'armadillo.organization.doctor'),
new NewRole('Nurse Practitioner', 'armadillo.organization.nursePractitioner'),
new NewRole('Patient', 'armadillo.microurb.billing'),
new NewRole('Microurb admin', 'armadillo.organization.admin'),
new NewRole('Microurb admin', 'armadillo.organization.admin'),
new NewRole('Microurb billing', 'armadillo.organization.billing'),
new NewRole('Respiratory therapist', 'armadillo.microurb.respiratoryTherapist'),
new NewRole('Microurb commercial contact', 'armadillo.microurb.practiceGrowthDirector')
];
var viewRoles = [];
for (var i = 0; i < armadilloRoles.length; i++) {
const role = armadilloRoles[i];
const viewRoleDto = new ViewRole(role.name, role.description);
// if (viewRoleDto[i].description.startsWith('armadillo.organization.')) {
// viewRoles.push(viewRoleDto[i]);
// }
viewRoles.push(viewRole);
}
console.log(viewRoles);
I have tried a variety of ways of implementing an if conditional with a startsWith() method.
I want to return just the ones that have armadillo.organization. as the description.
A good way would be to use reduce like this:
const matches = armadilloRoles.reduce(
(prev, cur) =>
cur.description.startsWith("armadillo.organization") ? [...prev, cur] : prev,
[]
);

Remove all Groups and children in a nodeJS app

i need help with my little nodeJS app. i need to create a function which will delete nested groups in a tree.
iv'e debugged my tree search recursion and it works great.
but my delete function not deleting anything.
i need to get to the parent and delete it from the array.
tree looks like that:
class Group {
constructor(name, parent) {
this.name = name;
this.parent = parent || null;
this.children = [];
this.users = new users || null;
}
}
class groups {
constructor() {
this.root = new Group('root');
}
}
working tree search function (feel free to use!)
and non functioning delete function
findGroupByName(name) {
if (!name)
return null;
return this._findGroupByNameInternal(this.root, name);
}
_findGroupByNameInternal(group, name) {
if (!group)
return null;
if (group.name === name)
return group;
for (const g of group.children) {
const result = this._findGroupByNameInternal(g, name);
if (!result)
continue;
return result;
}
}
removeByName(name) {
if (!this.children)
return;
const groupToRemove = this.findGroupByName(name);
if (groupToRemove) {
this.children = this.children.filter(g => g !== groupToRemove);
}
}
menu handler
function removeGroup(callback) { //need fixing
rl.question('Enter group name to delete: \n', (groupName) => {
let parentGroup = programdata.groups.findGroupByName(groupName);
programdata.groups.removeByName(groupName)
console.log(parentGroup);
callback()
})
}
function showGroups(callback) {
callback()
}
This isn't working for you because the group returned by _findGroupByNameInternal() isn't necessarily a child of the instance you called removeByName() on. So when you try to filter() the instance children, it may not be there — it may be a grandchild or deeper. You need to remove the group when you find it and still know the parent. There's a lot of way to do that, but here's a simple one:
class Groups {
constructor() {
this.root = new Group('root');
}
removeByName(name){
this.root.removeByName(name)
}
}
class Group {
constructor(name, parent) {
this.name = name;
this.parent = parent || null;
this.children = [];
}
removeByName(name){
// is name in children?
let index = this.children.findIndex(g => g.name === name)
if (index > -1) {
// delete it
this.children.splice(index, 1)
console.log(`removed ${name} from ${this.name}`)
} else {
// otherwise recurse on children
this.children.forEach(child => child.removeByName(name))
}
}
}
Here's a full snippet:
class Group {
constructor(name, parent) {
this.name = name;
this.parent = parent || null;
this.children = [];
}
removeByName(name){
let index = this.children.findIndex(g => g.name === name)
if (index > -1) {
this.children.splice(index, 1)
console.log(`removed ${name} from ${this.name}`)
} else {
this.children.forEach(child => child.removeByName(name))
}
}
}
class Groups {
constructor() {
this.root = new Group('root');
}
removeByName(name){
this.root.removeByName(name)
}
}
let groups = new Groups()
// Make some nested groups
for (let j=0; j < 5; j++){
let parent = groups.root
let group = new Group(`group_${j}`, parent )
parent.children.push(group)
parent = group
for (let i=0; i < 5; i++){
let group = new Group(`group_${j}_${i}`, parent )
parent.children.push(group)
}
}
// Delete the second second of group 3 (group_3_1)
groups.removeByName('group_3_1')
// Make sure group_3_1 is gone
console.log(groups.root.children[3].children.map(c => c.name))

create objects using factory in Javascript

I'm having trying to create two objects of type person using factory and on the first try I create the first element and the second attempt instead of creating the second element creates a new element but with the same characteristics as the first element
class Person
function Person(id, name) {
this.id = id;
this.name = name;
}
class Student extends Person
function Student(id, name) {
Person.call(this, id, name);
}
class Teacher extends Person
function Teacher(id, name) {
Person.call(this, id, name);
}
using function factory to create student and teacher
function Factory() {
this.createPerson = function(type, name) {
var person;
var idStudent = 0;
var idTeacher = 0;
switch (type) {
case "1":
person = new Student(idStudent++, name);
break;
case "2":
person = new Teacher(idTeacher++, name);
break;
}
return person;
}
}
class School has an array of person
function School(id) {
this.persons = [];
this.factory = new Factory();
this.personCreate = null;
this.createStudentAndTeacher = function() {
var type = prompt("Choose ? \n\n[1-Student | 2-Teacher ]");
var name = prompt("Write name?");
if (type !== null) {
this.personCreate = this.factory.createPerson(type,name);
this.persons.push(this.personCreate);
} else {
alert("need to choose");
}
}
}
created by default
var s = new School(1);
var btn = document.createElement('button');
btn.value = "create";
btn.onclick = function(){
s.createStudentAndTeacher();
}
my doubt is when I create the Student object with name "John", return student.id = 0 and student.name = John but when I create the new Student object with name "Elisa", return the same information student.id = 0 and student.name = John and in fact, should return student.id = 1 and student.name = Elisa and if I create new Teacher object with name "Jerry", return the same information student.id = 0 and student.name = John and in fact, should return teacher.id = 0 and teacher.name = Jerry
what I´m doing wrong?
The code has a bug. In the Factory definition, change this
function Factory() {
this.createPerson = function(type, name) {
var person;
var idStudent = 0;
var idTeacher = 0;
to this
function Factory() {
var idStudent = 0;
var idTeacher = 0;
this.createPerson = function(type, name) {
var person;
then use the console, run these lines.
var s = new School();
s.createStudentAndTeacher(); // john
s.createStudentAndTeacher(); // bob
s.persons[0] // id 0:john
s.persons[1] // id 1:bob
Your createPerson is redeclaring idStudent and idTeacher (and resetting them to 0). Try moving that code out of that block.

calling a function inside a function that uses prototype property

I am creating this Node...
function Node ( name, level, parent ) {
this.name = name;
this.level = level;
this.children = [];
this.parent = parent;
this.id = this.createId();
}
When I reference this.name, this.level, this.parent, and this.children everything works great in the function I made. When I try and reference this.id I get nothing.
This is my function for setting this.id...
Node.prototype.createId = function () {
var p = this.parent;
return p.name;
}
I don't know if Im calling it correctly in the Node function.
Pass this keyword as parameter in this.createId(); like following
function Node ( name, level, parent ) {
this.name = name;
this.level = level;
this.children = [];
this.parent = parent;
this.id = this.createId(this);
}
then in node do this
Node.prototype.createId = function (self)
{
var p = self.parent;
return p.name;
}

Categories

Resources