Nested Object.keys() are printing properties multiple times instead of only once - javascript

I have two objects that I need to loop through so I can use their properties later on. However if I print the variables each of them is printed twice. I understand that because I have the Object.keys() inside other Object.keys(). Is there any way to loop through these two objects and only get each variable one time?
My code:
Object.keys(newData.name).map(async key => {
Object.keys(newData._temp.images).map(async keyImage => {
console.log(newData.name[key].name,'printed 2x instead of once');
console.log(newData._temp.images[keyImage].rawFile.preview, 'printed 2x instead of once');
});
});
Thank you in advance.

your logic here of nesting the loops is wrong.
these 2 object does not seem to be connected to one another, meaning you do not need the data from the first loop in order to perform the other loops. just split it into 2 seperate loops, would save you both time and repititions:
let nameKeys = Object.keys(newData.name).map(key => newData.name[key].name);
let imagesKeys = Object.keys(newData._temp.images).map(keyImage =>
newData._temp.images[keyImage].rawFile.preview);
now you can access nameKeys and imageKeys whenever you want, and they will contain the values you previously logged. My naming might be a bit off tho, feel free to change that :D
Also, as others mentioned- no need for the async keyword... you do not perform any async operation inside (yet, at least. if thats what you're planning then go ahead and keep it).

These iterators do not need to be nested. The second iterator is not looping through an item of the first iterator.
Object.keys(newData.name).forEach(key => {
console.log(newData.name[key].name);
});
Object.keys(newData._temp.images).forEach(keyImage => {
console.log(keyImage[keyImage].rawFile.preview);
});
If you are only iterested in outputting data, then .map() is not the right function to use because this is used when you care about the return value. Use .forEach() if you just want to loop through things.
Also, the async keyword is not needed here.. unless you plan to do some async/await stuff in the loops later!

You could iterate over the indices once and then access the values in both arrays:
const names = Object.keys(newData.name);
const images = Object.keys(newData._temp.images);
for(let i = 0; i < Math.min(names.length, images.length); i++) {
const name = names[i];
const image = images[i];
//...
}

Related

How to take three different words from an array?

I want to create a function taking three random different words from an array
I followed React native filter array not working on string to filter the array. However, the filter is not working.
takeThreeWords=()=>{
for(i=0;i<3;i++){
rand =(max, min=0)=> Math.floor(Math.random()*max-min)
randomWord=()=> this.state.wordsBank[rand(this.state.wordsBank.length)]
let aRandomWord = randomWord()
this.setState(prevState=>({
wordsToUse:[...prevState.wordsToUse, aRandomWord],
wordsBank: prevState.wordsBank.filter(word=>word!== aRandomWord)
}))
The last line is to make sure that no words from wordsBank are taken twice. However, the function works just as if the last line does not exist. wordsToUse take three words, but sometimes they are the same...
Can you please point me out what I am missing ?
You are updating wordsBank via this.setState, but your loop keeps operating on the initial copy of wordsBank, which has not been filtered.
The cleanest fix is to not call this.setState multiple times in a loop.
let wordsBank = this.state.wordsBank;
let extractedWords = [];
while(extractedWords.length<3) {
let i = ~~(Math.random()*wordsBank.length);
extractedWords.push(wordsBank.splice(i, 1)[0]);
}
this.setState(prevState=>({
wordsToUse: [...prevState.wordsToUse, ...extractedWords],
wordsBank
}));

Is there a way to combine map and shift in Javascript?

I'm working with a buffer array that I am periodically checking. When I am mapping through the elements, I would like access the element using the shift method, this way I would get the next element in the array and would also remove it. Is there a way to do this in a map? Thank you!
I currently have a naive solution, which is prone to race conditions.
if (timestep) {
bufferArray.map((mvt) =>{
console.log(mvt)
});
bufferArray = [];
}
As I would like to go through the elements of the array one by one and remove the current element from the array. For this reason a simple and great solution is to use a while loop with the shift method. For example:
let arr = [0,1,2,3,4,5];
while (arr.length)
{
let current = arr.shift()
// do something with current
}

Possible to .push() to a dynamically named key?

I have an object that I would like to push an indeterminate amount of other objects to, using a loop. To keep it organized, I'd like to dynamically name the keys based on them amount of times the loop runs. I have the following:
let formsJson = {};
let counter = 1;
//savedForms are where the objects that I want to push reside
savedForms.forEach( form => {
formsJson['form'+counter] = JSON.parse(form.firstDataBit_json);
//This is where I'm having trouble
counter = counter + 1;
});
I can push the first bit of data fine, and name the key dynamically as well. But I need to push 2 more objects to this same dynamic key, and that's where I'm having trouble. If I try the obvious and do:
formsJson['form'+counter].push(JSON.parse(form.secondDataBit_JSON));
I don't get any output. Is there a way to accomplish this?
forEach() gives you access to the index already. No need to create the counter variable. Example usage. I would definitely recommend using a simple index, and not using the 'form'+counter key.
In your example, it's not clear to me that the value being assigned in the forEach loop is an array. So it's unclear if you can push to any given element in that. But generally that syntax should
Personally, I would prefer to have a function that outputs the entire value of the element. That would provide better encapsulation, testability, and help enforce default values. Something like:
function createItem(param1) {
let item = [];
item.push(param1.someElement);
if (foo) {
item.push(...);
} else {
item.push(...);
}
return item;
}
formsJson['form'+counter] = createItem( JSON.parse(form) )
So you're making formsJson['form'+counter] a by assigning the JSON parse, not an array as you want. Try this:
formsJson['form'+counter] = [];
formsJson['form'+counter].push(JSON.parse(form.firstDataBit_json));
formsJson['form'+counter].push(JSON.parse(form.secondDataBit_JSON));
Maybe you want to figure out something like this
savedforms.forEach((form, index) =>
formsJson[`form${index + 1}`] = [ JSON.parse(form.secondDataBit_JSON)])
Now you can push on the item
formsJson[`form${index + 1}`].push(JSON.parse(form.secondDataBit_JSON));`
Also here you'll save operation on incrementing it will be automaticly

Nested Map loop async/await vs nested for loop async/await

I have a nested map loop with async awaits where I do 2 promise.all statements.
The data is formatted in 1 large array in which contains possibly multiple arrays of objects.
The inner loop will map through the objects in an array, and the outer loop will map through the arrays within the main array.
I'm using map since it is easy to keep this functioning with parallel performance versus sequential. I'm not sure if it is worth keeping it parallel or if there is a better way of doing this (maybe a for-each loop).
Here is the code (simplified/summarized) that I am using currently.
const outerPromise = information.map(async order => {
const innerPromise = order.moreInformation.map(async singleOrder => {
if (something) {
const response = await axios({ ... });
return response.specificDataField;
}
});
const orders = await Promise.all(innerPromise);
return orders.filter((obj) => obj);
});
const orders = await Promise.all(outerPromise);
return orders;
Sorry if the formatting is slightly off, the indentation might be off, I couldn't get it to format properly.
Any help will be greatly appreciated. Thank you!
P.S. This is being written in JS/NodeJs (ExpressJs)
Edit:
I don't think the issue is with me filtering afterwards since it is the objects that would possibly come out null; I would need to filter after getting back the innerPromise (to see which are null?).
That being said, it is really the 2 map statements that make me feel as if there is a better way of doing this.

Best way to loop through array object

leagueInfo = {"data":[{"tier":"Gold"},{"tier":"Bronze"}]}
So far I have been doing 2 for loops like this:
for (const key of Object.keys(leagueInfo)) {
console.log('5on5 ranked', leagueInfo[key]);
// Array (2) is output
for (const values of leagueInfo[key]) {
console.log('5on5 ranked', values.tier );
// Output is :
// Gold
// Bronze
}
}
Do I really need 2 loops or is there a shorter way of doing this?
leagueInfo.data.forEach(item => console.log(item.tier));
There are several ways.
You could use methods from the lodash or underscore libraries, that are replicas of how the .foreach or for loops work.
If the data that you have is always the same and similar to the one posted you can do the following to iterate through the data items that you have in the array. Keep in mind that the first iteration you are doing is useless, since you could access the property directly.
var leagueInfo = {"data":[{"tier":"Gold"},{"tier":"Bronze"}]}
leagueInfo.data.forEach((item) => {
console.log(item);
console.log(item.tier);
})
There is dozens of ways to iterate objects or arrays. And usually with functions specifically adapted for certain goals in mind. if you want to only console.log iteration result you can use .map()
var leagueInfo = {"data":[{"tier":"Gold"},{"tier":"Bronze"}]};
Object.values(leagueInfo).map(function(dataArray) {
console.log('5on5 ranked', dataArray);
dataArray.map(function(values) {
console.log('5on5 ranked', values.tier );
})
})
And here's a link to W3Schools where you can find all possible actions with arrays.
https://www.w3schools.com/jsref/jsref_obj_array.asp

Categories

Resources