Please help me understand this Iterate Through the Keys of an Object with a for...in Statement

Tell us what’s happening:

Your code so far


let users = {
  Alan: {
    age: 27,
    online: false
  },
  Jeff: {
    age: 32,
    online: true
  },
  Sarah: {
    age: 48,
    online: false
  },
  Ryan: {
    age: 19,
    online: true
  }
};

function countOnline(obj) {
  // change code below this line
for (let user in users){
for (let data in user){

}
}
  // change code above this line
}

console.log(countOnline(users));

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-data-structures/-iterate-through-the-keys-of-an-object-with-a-for---in-statement

1 Like

So a for…in statement iterates through the key/value pairs in an object. So the reason the nested loop works is because you have nested objects inside of an object.

for (let user in users){

The first loop is looping through each key in users. The first loop it will grab Alan, then it will grab Jeff, then Sarah, and finally Ryan.

The nested loop is accessing the key value pairs inside each person object. So when the first loop is iterating through Alan, the nested loop will first grab age, then online. Then the first loop goes to Jeff and the nested loop goes back to age, then online, and so on until it makes it through each set of key value pairs for each person in the object “users”.

Does that make sense?

This would be useful if you didn’t know the key value pairs in an object. Otherwise you could do one loop and access the nested key value pairs with something like:

for (let user in users){
if (user.age >= 18) //do something
}

thanks i am still on it

i am not getting it, pls help

The job of countOnline is to return how many users have the property online set to true. If you look at the users object, you can see it is 2. Your job is to create the countOnline.

  1. You need a counter to store how many users are online.
  2. You need to loop through each user and check if the user is online, if he is, you increment the counter, if not, you ignore.
  3. You need to return the counter.

Hope this helps, give it a try, if you can’t get it to work, please post your code.

Hey @Benematics,
I am with you. I am stuck!

function countOnline(obj) {
  // change code below this line
  let i = 0;
  for(let user in obj){
   user.online ? i += 1: null;
  };
  return i;
  // change code above this line
}

I have tried this and I am just getting 0. I know this is probably obvious, but something is just not clicking for me so I am genuinely stuck.

I also tried

function countOnline(obj) {
  // change code below this line
let i = 0;
  for(let user in obj){
    for(let line in user){
      line == true ? i++ : null;
    }    
  }
  return i;
  // change code above this line
}

With the double == it returns 4, with the === it returns 0.

I am really lost. I get the concept. I get what we are trying to do. But I just don’t get it.

And the Get A Hint button returns a 404!

@Benematics

I’ve created a repl here: https://repl.it/@psbyron3/PuzzlingUglyPyramid

Hopefully this helps explain things.
As you work thru it, uncomment a console.log line to see what output you get.

Let me know if you have more q’s

@Gabester0

Check out my above answer, I think it may help you understand. Let me know if you have q’s

1 Like

Hey @psbyron3!

This was a huge help; thank you so much!

Your explanation was really impressive because I wasn’t sure it could be explained to me without just giving me the answer. But your repl really helped me just think things through more logically to realize what assumptions I was making.

Is it safe to say that the issue I was having was because I was not being specific enough with the second for…in loop? I was assuming that the js engine knew to loop through the nested object when in fact it didn’t?

Either way thank you so much!

@Gabester0

It’s not a matter of specificity in the second for loop. The second loop was not referencing what you thought it was.

let’s look at your code:

function countOnline(obj) {
  // change code below this line
let i = 0;
  for(let user in obj){
    for(let line in user){
      line == true ? i++ : null;
    }    
  }
  return i;
  // change code above this line
}

In the first for loop you are grabbing the key, user from obj. Then we take that user key and look at each line. This is the mistake. In for(let line in user) you thought user was the user object. It was actually just the key

When you thought you were passing in:

Alan: {
    age: 27,
    online: false
}

into your second for loop, you were actually passing in:

Alan

So what this line,for(let line in user) is doing is iterating through that string, Alan. And when you console.log(line) you will see a number, this is the string’s index. If you then reference the value of that index, you get back the character. For ex:

for (let line in user) {
   console.log(user[line])
}
// the loop iterates 4 times (because Alan is 4 characters long and the output would be:
// 'A'
// 'l'
// 'a'
// 'n'

What we are interested in the second for in loop is the value not the key. So in order to look at the value of the key, we need to reference the parent object with bracket notation obj[user]. The value in this case is an object, a user object.

(You could also use dot notation, but one step at a time. There are constraints to dot notation vs. bracket notation I could go into if needed)

Making sense?

@Gabester0 Your code is actually really close.

function countOnline(obj) {
  // change code below this line
  let i = 0;
  for(let user in obj){
   user.online ? i += 1: null;
  };
  return i;
  // change code above this line
}

What you missed is that line in the challenge explanation:
“Sometimes you may need to iterate through all the keys within an object.”

As @psbyron3 explained, when you use user.online you’re actually calling online on a key, which are just strings: Alan, Jeff, Sarah and Ryan. What you must do is to grab the value that key has, for example: obj[user].online.

@psbyron3 & @ghukahr,
Thanks for your help. I think I understand now.

When I asked if it was specificity I think I was trying to ask (in a non-technical way) if I was being imprecise.

Thanks!

After reading thru this a few times I think I get it but I kept getting 8 instead of 2 until I used a break and now it works and I pass the tests… Is this correct?

function countOnline(obj) {
  // change code below this line
  let onlineCount = 0;
  for (let user in users) {
    console.log(user)
    console.log(users[user].online)
    for (let data in user) {
      if (users[user].online === true) {
        onlineCount += 1;
        break;
      }
    }
  }
      return onlineCount;  // change code above this line
};

You don’t need the second loop at all, you are already in the individual user so you just access the object property like users[user].online. Don’t loop over objects if you don’t need to. Get rid of the inner loop and the break, you only need if (users[user].online) onlineCount++

Got it now, thanks so much! :smiley:

1 Like