Search in the multiply tree view doesn't work properly - javascript

have a problem with the implamantation search in the multiple tree view.
Can check the code in the link.
In the group we have childGroup and list, we have to search lists and groups names. (check data in the data.js file)
Think the problem is somewhere here.
const search = (items, term) => {
return items.reduce((acc, item) => {
if (contains(item.name, term)) {
acc.push(item);
} else if (item.childGroupList?.length) {
let newGroupsItems = search(item.childGroupList, term);
if (newGroupsItems?.length) {
item.childGroupList = newGroupsItems;
acc.push(item);
}
} else if (item.list?.length) {
let newListItems = search(item.list, term);
if (newListItems?.length) {
item.list = newListItems;
acc.push(item);
}
}
return acc;
}, []);
};

There were a few issues in your recursive search.
Your if, else if, else if chain should be independent. They should really be three if blocks.
You need to push the result only after when all the searches are done at a certain level. I got a copy of the item and make childGroupList and list properties empty([]) initially and update them when a search is successful.
Try like this.
// main search function, here is the problem
const search = (items, term) => {
return items.reduce((acc, item) => {
let itemCopy = JSON.parse(JSON.stringify(item));
itemCopy.childGroupList = [];
itemCopy.list = [];
let found = false;
if (contains(item.name, term)) {
found = true;
}
if (item.childGroupList?.length) {
let newGroupsItems = search(item.childGroupList, term);
if (newGroupsItems?.length) {
found = true;
itemCopy.childGroupList = newGroupsItems;
}
}
if (item.list?.length) {
let newListItems = search(item.list, term);
if (newListItems?.length) {
found = true;
itemCopy.list = newListItems;
}
}
if (found) {
acc.push(itemCopy);
}
return acc;
}, []);
};
Code sandbox => https://stackblitz.com/edit/react-rmrlj1?file=src%2FApp.js

Related

reducing the If else condtion code in javascript

I wrote a code to fetch the data present and store it in Array format but I thing I have wrote code multiple times can It be possible to minimize the code as its too long
let topicsValue = ["requiredType.*", "Entry.*", "token.*", "RestAPI.*"];
let Topic = [],
rest = ["required", "unrequired"],
final = ["createInput", "mustPossible", "finalOutput"];
topicsValue.map((data) => {
let requiredType, entries, token, restAPI;
if (data.split(".")[1].includes("*")) {
if (data.split(".")[0].includes("requiredType")) {
for (const value of final) {
requiredType = data
.split(".")[0]
.replace("requiredType", "required_type")
.concat(`.${value}`);
Topic.push(requiredType);
}
}
if (data.split(".")[0].includes("Entry")) {
for (const value of final) {
entries = data
.split(".")[0]
.replace("Entry", "entries")
.concat(`.${value}`);
Topic.push(entries);
}
for (const value of rest) {
entries = data
.split(".")[0]
.replace("Entry", "entries")
.concat(`.${value}`);
Topic.push(entries);
}
}
if (data.split(".")[0].includes("token")) {
for (const value of final) {
token = data
.split(".")[0]
.replace("token", "tokens")
.concat(`.${value}`);
Topic.push(token);
}
for (const value of rest) {
token = data
.split(".")[0]
.replace("token", "tokens")
.concat(`.${value}`);
Topic.push(token);
}
}
if (
data.split(".")[0].includes("RestAPI") &&
!data.split(".")[0].includes("RestAPIAction")
) {
restAPI = data
.split(".")[0]
.replace("RestAPI", "restAPI")
.concat(`.deploy`);
Topic.push(restAPI);
}
} else {
if (data.split(".")[0].includes("requiredType")) {
if (!rest.includes(data.split(".")[1])) {
requiredType = data
.split(".")[0]
.replace("requiredType", "required_type")
.concat(`.${data.split(".")[1]}`);
Topic.push(requiredType);
}
}
if (data.split(".")[0].includes("Entry")) {
if (rest.includes(data.split(".")[1])) {
entries = data
.split(".")[0]
.replace("Entry", "entries")
.concat(`.${data.split(".")[1]}.demo`);
Topic.push(entries);
} else {
entries = data
.split(".")[0]
.replace("Entry", "entries")
.concat(`.${data.split(".")[1]}.demo`);
Topic.push(entries);
}
}
if (data.split(".")[0].includes("token")) {
if (rest.includes(data.split(".")[1])) {
token = data
.split(".")[0]
.replace("token", "tokens")
.concat(`.${data.split(".")[1]}`);
Topic.push(token);
} else {
token = data
.split(".")[0]
.replace("token", "tokens")
.concat(`.${data.split(".")[1]}`);
Topic.push(token);
}
}
if (
data.split(".")[0].includes("RestAPI") &&
!data.split(".")[0].includes("RestAPIAction")
) {
restAPI = data
.split(".")[0]
.replace("RestAPI", "restAPI")
.concat(`.deploy`);
Topic.push(restAPI);
}
}
});
console.log(Topic);
Is there any possible way I can reduce the code without effecting the output
As the requirement of the code is like if the topicValue contain * or the other value so I wrote this long code and now I am trying to minimize the code so its look short and effective.
I made refactoring only if(true) part of your code. You can implement the else part by yourself. I didn't run the code, spend any time for proper naming, etc. So it was quick refactoring to give you an idea. I think there is a mistake in else block because both if and else parts of tokens and Entry are doing the same thing.
let replace = {
requiredType: 'required_type',
Entry: 'entries',
token: 'tokens',
RestAPI: 'restAPI'
}
const run = () => {
topicsValue.map((data) => task(data));
}
const task = (data) => {
data.split(".")[1].includes("*") ? funcIf(data) : funcElse(data);
}
const funcIf = (data) => {
for (const key in replace) {
if (data.split(".")[0].includes(key)) commonTask(key, data);
}
}
const commonTask = (key, data) => {
if (key == 'RestAPI' && data.split(".")[0].includes("RestAPIAction")) return;
final.forEach(value => Topic.push(makeOutput(key, value, data)));
}
const makeOutput = (key, value, data) => {
return data.split(".")[0]
.replace(key, replace[key])
.concat(key == 'restAPI' ? '.deploy' : `.${value}`);
}
Try using the && operator.
if(y==1 && x == 1) {
do somthing
}
it only runs if both statements are true.

Modeling a prerequisite schema of courses as a tree

I'm creating a website to interact with courses and their prerequisites.
This is for free, isn't a homework and I'm using this project to learn MERN
I did this tree schema which represents all courses and their dependencies.
Notice that a course can have more than one prerequisite.
So I'm having rough time translating this into TDA. I have been trying with multi parents tree but I have no results due to:
Can't recreate multiparents into one node
Can't traverse a tree with implementations so I can't know which courses are available
I was using this Tree/Node definition in JS. I didn't try with Python but I have no problem in using another language even when I know language isn't the problem.
class Tree {
constructor(root) {
this._root = root || null;
}
_traverse(callback) {
const self = this;
function goThrough(node) {
callback(node);
node.children.forEach((child) => {
goThrough(child);
});
}
goThrough(this._root);
}
_addNode(value, parentValue) {
const newNode = {
value,
children: []
};
if (this._root === null) {
this._root = newNode;
return;
}
this._traverse((node) => {
if (node.value === parentValue) {
node.children.push(newNode);
}
});
}
_removeNode(value) {
this._traverse((node) => {
node.children.forEach((childNode, index) => {
if (childNode.value === value) {
node.children.splice(index, 1);
}
});
})
}
_search(value) {
let returnNode = 'Not Found';
this._traverse((node) => {
if (node.value === value) {
returnNode = node;
}
});
return returnNode;
}
_displayLeafs(parentValue) {
const parentNode = typeof parentValue === 'string' ? this._search(parentValue) : parentValue ;
let leafsRet = [];
if (parentValue.children && !parentValue.children.length) {
return parentValue;
}
parentNode.children.forEach((child) => {
leafsRet.push(this._displayLeafs(child));
});
return leafsRet.flat();
}
}
class Node {
constructor(value, children) {
this.value = value;
this.children = children;
}
}
const malla = new Tree();
malla._addNode('root');
malla._addNode('CMB1000','root');
malla._addNode('CMB1001','root');
malla._addNode('CIT1000','root');
malla._addNode('FIC1000','root');
malla._addNode('CBQ100','root');
malla._addNode('CIT1010','CIT1000');
console.log(malla._displayLeafs('root'));
I didn't follow inserting new nodes because I'm not getting results as expected.
Can anyone give a hint about a tree implemention that may I know? Or maybe a better approach to this situation?
Thanks for your time!

How would I change this code to a different format? (Javascript)

The code below is the code that I have written:
function singer(artist) {
var songs = [];
for(var i = 0; i < music.length;i++ ){
if(music[i].artist.indexOf(artist) > -1) {
songs.push(music[i].name);
}
}
return songs;
}
The code that I want to look similar to the function singer(artist) code is this:
const genreCount = () => {
const genres = music.reduce((result, cur) => {
cur.genres.forEach(g => {
if (result.hasOwnProperty(g)) {
result[g] += 1;
}
else
result[g] = 1;
});
return result;
}, {});
return genres;
}
I am unfamiliar with this type of format in Javascript, how would I change it so that const genreCount will look like function singer(artist).
This is what you will get if you want to change that function:
function genreCount() {
const genres = music.reduce(function(result, cur) {
cur.genres.forEach(function(g) {
if (result.hasOwnProperty(g)) {
result[g] += 1;
}
else
result[g] = 1;
});
return result;
}, {});
return genres;
}
or (if you want to assign that fucntion to a const anyway):
const genreCount = function() {
const genres = music.reduce(function(result, cur) {
cur.genres.forEach(function(g) {
if (result.hasOwnProperty(g)) {
result[g] += 1;
}
else
result[g] = 1;
});
return result;
}, {});
return genres;
}
You just should replace arrow functins with the regular function expressions. But I don't know why do you need that.
this style is called functional programming
const singer = artist => music.filter(m => artist.indexOf(m.artist) > -1).map(m => m.name)
here is a good interactive tutorial if you are interested
Functional Programming in Javascript
UPDATE:
oops, sorry for misunderstanding your questions
here is genreCount rewritten with for-loop:
function genreCount(){
const genres = {};
for(var i=0; i<music.length; i++){
var g = music[i]
if (genres.hasOwnProperty(g)) {
genres[g] += 1;
}
else{
genres[g] = 1;
}
}
return genres;
}

How to call method recursively in typescript

I want to call the filterArr inside the filterArr. Here is my implementation.
filterArr(array, search) {
var result = [];
array.forEach((a)=> {
var temp = [],
o = {},
found = false;
if (a.name === search) {
this.o.name = a.name;
found = true;
}
if (Array.isArray(a.children)) {
temp = this.filterArr(a.children, search);//***Cannot read property 'filterArr' of undefined***
if (temp.length) {
this.o.children = temp;
found = true;
}
}
if (found) {
result.push(o);
}
});
return result;
}
How to call the filterArr method without any error?
You have to use Arrow function to get hold on correct this, so you need to change array.forEach(function (a) { to use `Arrow function
array.forEach((a) => {

Javascript: deep find object in tree, then return object and the path to it through the tree

I've got a data structure that looks something like this:
let tree = {
id: 1,
name: "Some Name",
children: [
{
id: 2,
name: "Child 1",
children: [...more nested objects...]
}
]
};
I've written a recursive function to find a given object within that tree, but I now need to also return the path through the tree to the object that is returned. I'm trying to figure out how to modify my search function to do this.
Search function:
_findInTree = (id, tree) => {
let result;
if (tree.id === id) {
result = tree;
} else {
for (let child of tree.children) {
if (child.id === id) { result = child; }
result = this._findInTree(id, child);
if (result) { break; }
}
}
return result;
}
You'll need the array index, so you can either track it outside the for-of and then use it on the path, or use Array#some instead (or use a boring old for).
Here's tracking the index outside the for-of — I also added an else I think was probably pretty important: :-)
_findInTree = (id, tree, path = "") => {
let result;
let index;
let rv;
if (tree.id === id) {
result = tree;
} else {
index = 0;
for (let child of tree.children) {
if (child.id === id) {
result = child;
break;
}
rv = this._findInTree(id, child, path + "[" + index + "]");
if (rv != null) {
return rv;
}
++index;
}
}
return { result, path };
};
Obviously, adjust the format of path as you see fit. (Doesn't have to be a string, for instance, could be an array.)
Here's the some solution:
_findInTree = (id, tree, path = "") => {
let result;
let rv = null;
if (tree.id === id) {
result = tree;
} else {
tree.children.some((child, index) => {
if (child.id === id) {
result = child;
return true;
}
rv = this._findInTree(id, child, path + "[" + index + "]");
if (rv) {
return true;
}
});
}
return rv || { result, path };
};
So T.J. Crowders position ended up having a bug around recording the path, and I ended up tweaking the solution to get the following, which works excellently.
_findInTree(id, tree) {
if (tree.id === id) {
let path = [tree.name];
return {result: tree, path};
} else {
for (let child of tree.children) {
let tmp = this._findInTree(id, child);
if (!_.isEmpty(tmp)) {
tmp.path.unshift(tree.name);
return tmp;
}
}
return {};
}
}
As For me, I need to change Kevin Whitaker code to this one
_findInTree(id, tree) {
if (tree.id === id) {
let path = [tree.name];
return {result: tree, path};
} else if (tree.children) { //THIS IS THE CHANGES THAT I NEED
for (let child of tree.children) {
let tmp = this._findInTree(id, child);
if (!_.isEmpty(tmp)) {
tmp.path.unshift(tree.name);
return tmp;
}
}
return {};
}
}

Categories