Hopefully anybody else struggling with this finds this useful
This isn’t about passing the exercise! I’ve managed to do that contextually rather than specifically knowing really whats going on here. So I thought I’d set myself my own challenge to try and solidify my understanding of whats going on with for…in loops.
Rather than returning the count of online users, I thought to myself “how would I return an array of the ages of each user?” - The goal therefore is for ‘console.log(countOnline(users)’ to return [27, 32, 48, 19].
Here is how I did it!
function countOnline(obj) {
// change code below this line
let ages = []; //creates ages array to push age values in to
for (let prop1 in obj) { //iterates through each key within the object
for (let prop2 in obj[prop1]) { //iterates through each key within the nested object of prop1
if (prop2 == "age") { //only push the value when prop2 is looking at age (not online)
ages.push(obj[prop1][prop2]); //push the value of the key to the array we made
}
}
}
return ages; //function returns the ages array
// change code above this line
}
Notice how (unexplained in the exercise) the variables we create, in my case ‘prop1’ and ‘prop2’, are just placeholders that essentially just take the form of “something that is changing on each iteration of the loop”.
You can name these variables whatever you like, but to me it seems to make sense that you’d refer to them as property/prop followed by the level of the property within the object that you’re changing for each iteration.
Because the second level of the users object is a nested object, we have to use the if statement to differentiate between ‘age’ and ‘online’. Whilst iterating through the loop, ‘prop2’ will take one of these values on one iteration, and the other value on the next iteration.
Hopefully someone finds this useful! Ninjas please do let me know if I haven’t explained anything correctly
Great that you have additional thoughts about this task!
I replicated the task this way:
function countOnline(obj) {
let ages = [];
for (let name in obj) {
ages.push(obj[name]["age"]);
}
return ages;
}
I directly go into the age property,
because what would happen,
if every user would have 50 instead of 2 properties?
The algorithm would compare every of these 50 properties with “age”.
Additionally, we can include: if (obj[name]["age"]){...}
to be sure to only include users with an age property.
Great job expanding on the lesson. This kind of thinking will speed up your learning in greater magnitudes.
Correct. Except semantically they are locally scoped variables.
Correct again. And you touched one of the 2 hardest things according to this classic joke
There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors.
Variables should always have meaningful names. Ideally a person would be able to guess the purpose of the variable by it’s name. If you will have a short-lived scope, like in a loop, sometimes it’s easier to use a single letter. But that’s only really for tracking indexes.
This part right here is not really needed since you hard coded the string age.
if (prop2 == "age") {
ages.push(obj[prop1][prop2]);
}
But you’re thinking is right on track, because now you can abstract this function into a more generic and re-usable function like this.
function listOfUserProp(obj, prop) {
// change code below this line
let filtered = [];
for (let user in obj) {
// you can also reference the previous variable here
for (let userProp in user) {
if (userProp == prop) {
ages.push(user[userProp]);
}
}
}
return filtered; //function returns the ages array
// change code above this line
}
@miku86 your solution is a lot nicer than mine! I think perhaps I got too bogged down in iterating through keys that I overlooked you can just pull these values out specifically, per iteration of the top level (user)
@JM-Mendez thanks for confirming some of my thoughts on this! I struggled to understand your final example for a little bit because I didn’t notice the function had been changed to bring in a property element as well. That seems like a really handy bit of code though!
I have a quick aside question if either of you could confirm my understanding with this… Within the function, in this instance, we can essentially use ‘obj’ & ‘users’ interchangeably seeing as we only have the one object to worry about. If we had multiple objects we’d be best off referring to ‘obj’ in our for/in statements to allow the function to work correctly across all objects correctly?