Traverse all possible paths of an array with javascipt using async - javascript

I' am a begginer with Javascript and I am currently try to find all possible paths of a returned JSON object from an axios GET request.Every item can belong to one or more groups, and one group can belong to an other group.
e.g.
{
"name": "item1",
"groupNames": [ "GROUPA" ]
}
{
"name": "GROUPA",
"groupNames": [
"GROUPB"
]
}
....
{
name: "GROUPZ"
"groupNames": [
]
}
My issue is that my code is working only if a item name has only one parent groupName in the array.
What if we have more than one parentgroupNames? e.g
{
"name": "item1",
"groupNames": [ "GROUPA","GROUC",GROUBD ]
}
...
My current code:
let parent = 'item1';
do{
let endpoint = ${process.env.OPENHAB_HOST}:${process.env.OPENHAB_PORT}/rest/items/${parent}?recursive=false
result = await getAxiosRequest(endpoint,{},res); // get request to specific endpoint
parent = result.data.groupNames; }
while(result.data.groupNames.length !== 0 )

To find all the parent groups for an item that has multiple parent groups, you can modify your code as follows:
Initialize an array called parents to store the parent groups that you find.
In the loop, instead of assigning parent to result.data.groupNames, iterate over result.data.groupNames and add each group to the parents array.
After the loop, parents will contain all the parent groups for the given item.
Here's how the modified code would look:
let parent = 'item1';
let parents = []; // initialize array to store parent groups
do {
let endpoint = `${process.env.OPENHAB_HOST}:${process.env.OPENHAB_PORT}/rest/items/${parent}?recursive=false`;
result = await getAxiosRequest(endpoint,{},res); // get request to specific endpoint
result.data.groupNames.forEach(group => parents.push(group)); // add each group to the parents array
parent = result.data.groupNames;
} while(result.data.groupNames.length !== 0);
console.log(parents); // array of parent groups
This should work even if the item has multiple parent groups.

It is not entirely clear what the end result should be after the loop has ran, but I'll assume you would maybe collect the paths from the given item in an array.
As indeed you can get multiple groups, you need to either store them in a queue/stack for later processing, or use recursion (for the same reason).
Here is how it could look with recursion:
function async visit(parent) {
const endpoint = `${process.env.OPENHAB_HOST}:${process.env.OPENHAB_PORT}/rest/items/${parent}?recursive=false`;
const {data} = await getAxiosRequest(endpoint, {}, res);
const results = [];
for (const group of data.groupNames) {
results.push(...(await visit(group)).map(path => path.concat(group)));
}
return results;
}
visit('item1').then(paths => {
// ....
});

Related

Updating Json Value with that of another Json

I want to update automatically the value of comments_list with the values in the comments JSON object
const tweet = JSON.stringify({"tweet_id":1,"created_at":"2022-06-28","comments_list":[]})
const comments = JSON.stringify({"tweet_id":1,"commenter_id": 2"commenter_first_name":"tito","commenter_username":"tito_lulu"})
The final output should look like this
{"tweet_id":1,"created_at":"2022-06-28","comments_list":[{"commenter_id": 2"commenter_first_name":"tito","commenter_username":"tito_lulu"}]}
I'd work with those strings in an object form, otherwise string-manipulation could be slow in some cases.
This is by no means the fastest solution but perhaps the idea behind it can be helpful.
const tweet = [{
"tweet_id": 1,
"created_at": "2022-06-28",
"comments_list": []
}]; // There could be many tweet objects so wrap it in an array
const comments = [{
"tweet_id": 1,
"commenter_id": 2,
"commenter_first_name": "tito",
"commenter_username": "tito_lulu"
},
{
"tweet_id": 1,
"commenter_id": 5,
"commenter_first_name": "me-too",
"commenter_username": "me294"
}
]; // Same here, could be many comments right?
let UpdatedTweets = [];
// There are faster ways to do this, but for your question
tweet.forEach((tweet, tweetIndex) => {
// Loop each tweet
let post = tweet;
comments.forEach((comment, commentIndex) => {
if (comment.tweet_id == tweet.tweet_id) {
// we have a match lets combine them
tweet.comments_list.push({
commenter_id: comment.comment_id,
commenter_first_name: comment.commenter_first_name,
commenter_username: comment.commenter_username
});
}
});
UpdatedTweets.push(post);
});
console.log(JSON.stringify(UpdatedTweets));
The general idea is:
Parse the JSON into JS objects
Update the target object with the complementary information
Stringify the target object into JSON (only if you need to, eg. send the data to some other machine)
In your case:
const tweet = JSON.stringify({"tweet_id":1,"created_at":"2022-06-28","comments_list":[]});
const comments = JSON.stringify({"tweet_id":1,"commenter_id": 2,
"commenter_first_name":"tito","commenter_username":"tito_lulu"});
let o_tweet = JSON.parse(tweet)
, o_comments = JSON.parse(comments)
;
if (Array.isArray(comments)) { // Test whether that is a single or multiple comments
comments.forEach( c => { o_tweet.comments_list.push(c); });
} else {
o_tweet.comments_list.push(o_comments);
}
console.log(o_tweet);
// Only if needed:
// let newtweet = JSON.stringify(o_tweet)

Extract unique values of a key in a object - Javascript/d3 legend

Consider the following simplified csv file
x,y,names
1,2,group1
3,2,group2
4,3,group1
7,8,group3
3,5,group2
which I am reading in with d3.csv and afterwards apply a some function on it
d3.csv('file_name.csv').then(data => {
render(dataset)
});
Could someone explain to me how I could extract the unique strings in the category names and store them in a list
---> iam_a_list = [group1, group2, group3]
The elements in this list will later be used as text for a legend in a plot.
You can use a set to get unique results. Just loop over your data and make an array of all the names. Then make a set, which will remove all the duplicates and give you a unique list.
Using .map() and d3.set().values()
let uniqueListOfNames= []
d3.csv('file_name.csv').then(data => {
// listOfNames = ['group1', 'group2', 'group1', 'group3', 'group2']
const listOfNames = data.map(row => row.names)
// uniqueListOfNames = ['group1', 'group2', 'group3']
uniqueListOfNames = d3.set(listOfNames).values()
});
Using a loop.
let uniqueListOfNames= []
d3.csv('file_name.csv').then(data => {
const listOfNames= []
for (const row of data) {
listOfNames.push(row.names)
}
// listOfNames= ['group1', 'group2', 'group1', 'group3', 'group2']
// uniqueListOfNames = ['group1', 'group2', 'group3']
uniqueListOfNames = d3.set(listOfNames).values()
});

Javascript ForEach on Array of Arrays

I am looping through a collection of blog posts to firstly push the username and ID of the blog author to a new array of arrays, and then secondly, count the number of blogs from each author. The code below achieves this; however, in the new array, the username and author ID are no longer separate items in the array, but seem to be concatenated into a single string. I need to retain them as separate items as I need to use both separately; how can I amend the result to achieve this?
var countAuthors = [];
blogAuthors = await Blog.find().populate('authors');
blogAuthors.forEach(function(blogAuthor){
countAuthors.push([blogAuthor.author.username, blogAuthor.author.id]);
})
console.log(countAuthors);
// Outputs as separate array items, as expected:
// [ 'author1', 5d7eed028c298b424b3fb5f1 ],
// [ 'author2', 5dd8aa254d74b30017dbfdd3 ],
var result = {};
countAuthors.forEach(function(x) {
result[x] = (result[x] || 0) + 1;
});
console.log(result);
// Username and author ID become a single string and cannot be accessed as separate array items
// 'author1,5d7eed028c298b424b3fb5f1': 15,
// 'author2,5dd8aa254d74b30017dbfdd3': 2,
Update:
Maybe I can explain a bit further WHY on what to do this. What I am aiming for is a table which displays the blog author's name alongside the number of blogs they have written. However, I also want the author name to link to their profile page, which requires the blogAuthor.author.id to do so. Hence, I need to still be able to access the author username and ID separately after executing the count. Thanks
You could use String.split().
For example:
let result = 'author1,5d7eed028c298b424b3fb5f1'.split(',')
would set result to:
['author1' , '5d7eed028c298b424b3fb5f1']
You can then access them individually like:
result[1] //'5d7eed028c298b424b3fb5f1'
Your issue is that you weren't splitting the x up in the foreach callback, and so the whole array was being converted to a string and being used as the key when inserting into the results object.
You can use array destructuring to split the author name and blog id, and use them to optionally adding a new entry to the result object, and then update that result.
countAuthors = [
['author1', 'bookId1'],
['author2', 'bookId2'],
['author1', 'bookId3'],
['author1', 'bookId4'],
['author2', 'bookId5']
]
var result = {};
countAuthors.forEach(([author, id]) => {
if (result[author] === undefined) {
result[author] = {count: 0, blogIds: []};
}
result[author].count += 1;
result[author].blogIds.push(id);
});
console.log(result);

JS - Pushing data into JSON structure using forEach loops on Arrays

I am attempting to extract JSON values (from structure called jsonWithListOfStatesAndCounters) if it matches with an element in my inputted array (inputedJurisdictionArray). My inputed array contains sting values that include singular or multiple state names (i.e. var inputedJurisdictionArray = ["Iowa", "California, Indiana, Delaware", "Florida"]). The singular State values in this array are handled normally at the end, but the multiple state values is where it gets tricky. I am using split() in order to turn them into another array so they can get processed one by one. Anytime one of the states from this inputed array matches with a "state" value in jsonWithListOfStatesAndCounters, I am extracting it into another JSON structure and pushing it at the end of every block into my initial variable myJurisdictionJSON. The problem I am having is that once these forEach loops are completed, I am still left with my original values in myJurisdictionJSON, instead of the val and counter that should be extracted. The jsonWithListOfStatesAndCounters definitely contains the values that should match with the elements of my inputedJurisdictionArray, but the information is not being pushed into myJurisdictionJSON. What am I doing wrong? Any tips/pointers will be helpful.
var myJurisdictionJSON = [{
jurisdiction_val: 'jurisdiction_val',
jurisdiction_counter: 'jurisdiction_counter'
}];
inputedJurisdictionArray.forEach(function each(item) {
if (Array.isArray(item)) {
item.forEach(each);
} else {
var jurisdictionInput = item;
jsonWithListOfStatesAndCounters.forEach(function each(item) {
if (Array.isArray(item)) {
item.forEach(each);
} else {
if (jurisdictionInput.includes(",") === true){//Checking if more than one jurisdiction in string
var jurisdictionArr = jurisdictionInput.split(", ");
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
jurisdictionArr.forEach(function(element) {
if (myJurisdictionJSON.jurisdiction_counter == 'jurisdiction_counter'){ // If nothing is pushed into our predefined JSON object
if (jurisdictionState.toLowerCase() == trim(element.toLowerCase())) {
var jurisdictionJSON_inner = {
jurisdiction_val: element,
jurisdiction_counter: jurisdictionCounter
};
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}else if (myJurisdictionJSON.jurisdiction_counter != 'jurisdiction_counter'){ // if an item has been pushed into myJurisdictionJSON, append the next items
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
if (jurisdictionState.toLowerCase() == trim(jurisdictionInput.toLowerCase())) {
jurisdictionJSON_inner.jurisdiction_val = jurisdictionJSON_inner.jurisdiction_val + ", " + jurisdictionInput;
jurisdictionJSON_inner.jurisdiction_counter = jurisdictionJSON_inner.jurisdiction_counter + ", " + jurisdictionCounter;
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}
});
}
else{// if only one jurisdiction state in jurisdictionInput string
var jurisdictionCounter = item.jurisdictionCounter;
var jurisdictionState = item.jurisdictionState;
if (jurisdictionState.toLowerCase() == trim(jurisdictionInput.toLowerCase())) {
var jurisdictionJSON_inner = {
jurisdiction_val: jurisdictionInput,
jurisdiction_counter: jurisdictionCounter
};
myJurisdictionJSON.push(jurisdictionJSON_inner);
return;
}
}
}
});
I'm not totally sure the output is what you want but it's close.
// input data as per your example
let inputedJurisdictionArray = [
'Iowa',
'California, Indiana, Delaware',
'Florida'
];
// I had to make this part up. It's missing from the example
let jsonWithListOfStatesAndCounters = [{
jurisdictionCounter: 2,
jurisdictionState: 'Florida'
},
{
jurisdictionCounter: 4,
jurisdictionState: 'Indiana'
},
{
jurisdictionCounter: 3,
jurisdictionState: 'Texas'
}
];
// first, fix up inputedJurisdictionArray
// reduce() loops over each array element
// in this case we're actually returning a LARGER
// array instead of a reduced on but this method works
// There's a few things going on here. We split, the current element
// on the ','. Taht gives us an array. We call map() on it.
// this also loops over each value of the array and returns an
// array of the same length. So on each loop, trim() the whitespace
// Then make the accumulator concatenate the current array.
// Fat arrow ( => ) functions return the results when it's one statement.
inputedJurisdictionArray = inputedJurisdictionArray.reduce(
(acc, curr) => acc.concat(curr.split(',').map(el => el.trim())), []
);
// now we can filter() jsonWithListOfStatesAndCounters. Loop through
// each element. If its jurisdictionState property happens to be in
// the inputedJurisdictionArray array, then add it to the
// myJurisdictionJSON array.
let myJurisdictionJSON = jsonWithListOfStatesAndCounters.filter(el =>
inputedJurisdictionArray['includes'](el.jurisdictionState)
);
console.log(myJurisdictionJSON);

Create an array of specific elements from another array?

I have an array that can't be changed in terms of the element positions:
var array = ['item1', 'section1', 'section2', 'section3', 'section4', 'section5', 'prod1', 'prod2']
I want to make a new array from 'array' that takes the elements from position 1 - 5 (so all the section elements). It needs to be by position as the section elements make change by name.
var array2=array.slice(1,6)
See here for more information.
let's say we have an array like this
const FILES_WITH_10_ASSETS = [
'../assets/uploads/Desktop-300x600.jpeg',
'../assets/uploads/Desktop-728x90.png',
'../assets/uploads/Mobile-160x600.jpeg',
'../assets/uploads/Mobile-300X50.jpeg',
'../assets/uploads/Mobile-320x50.jpeg',
'../assets/uploads/Mobile-320x480.jpeg',
'../assets/uploads/Mobile-1024x768.jpeg',
'../assets/uploads/Tablet-300x250.jpeg',
'../assets/uploads/Tablet-Interstitial-320x480.gif',
'../assets/uploads/Tablet-Interstitial-320x480.jpeg'
];
now we want some specific items from an array, we will create a function for this, here I have stored the function in an constant for further use
const SELECT_ASSETS = function(assetName: string) {
let filtered_assets: string[] = [];
for (let i in FILES_WITH_10_ASSETS) {
if (FILES_WITH_10_ASSETS[i].includes(assetName) === true) {
filtered_assets.push(FILES_WITH_10_ASSETS[i]);
}
}
return filtered_assets;
};
and we call the method like this in our file
const ASSETS_NAME = SELECT_ASSETS(ASSET_NAME);
now we can pass the assets name to any function or method, if we pass the ASSET_NAME as Tablet we will get all three tablet paths, or if we change it to Mobile, we will get all five Mobile paths

Categories

Resources