0

I have objects (people) inside an array (group) inside an object (data) like so:

const data = {
  g1 : [
    {"name" : "Jack", "age" : 32},
    {"name" : "Jill", "age" : 44}    
  ],
  g2 : [
    {"email" : "[email protected]", "city" : "Berlin", "age" : 14},
    {"email" : "[email protected]", "city" : "Stockholm", "age" : 22}
  ]
}

Say I want to console.log all age property values, I try:

for (const group in data) {
  for (const person of group) {
    console.log(person.age)
  }
}

This does not work. It seems for (const group in data) is only looping over the names of it's children. I assume I should not use for...in in this case, but what can I use? Or is it somehow possible to use for...in?

The reason I'm confused is because in for example PHP I could do:

<?php

$data = [
    "g1" => [
        [ "name" => "Jack", "age" => 32 ],
        [ "name" => "Jill", "age" => 44 ]
    ],
    "g2" => [
        [ "email" => "[email protected]", "city" => "Berlin", "age" => 14 ],
        [ "email" => "[email protected]", "city" => "Stockholm", "age" => 22 ]
    ]
];


foreach ( $data as $group ) {
    foreach ( $group as $person ) {
        echo $person[ 'age' ];
    }
}

and in would work.

2
  • 1
    You'd need const person of data[group] since group is the key. Another way is to use Object.values(data).forEach(group => group.forEach(person => console.log(person.age))); Commented Dec 27, 2019 at 17:08
  • Since you found out that the outer loop gets you "g1" and "g2", this is basically a dupe of stackoverflow.com/questions/4244896/… Commented Dec 27, 2019 at 17:12

8 Answers 8

3

One easier way is:

const data = {
  g1: [{
      "name": "Jack",
      "age": 32
    },
    {
      "name": "Jill",
      "age": 44
    }
  ],
  g2: [{
      "email": "[email protected]",
      "city": "Berlin",
      "age": 14
    },
    {
      "email": "[email protected]",
      "city": "Stockholm",
      "age": 22
    }
  ]
};

console.log(Object.values(data).map(p => p.map(o => o.age)).flat());

Sign up to request clarification or add additional context in comments.

Comments

2

The for...in construct will provide you only with the keys of an object, not its values. In your outer loop:

for (const group in data) { ... }

... the variable group will be set to g1, then g2, not to the value of the group. To get the value (i.e., the person), you need to index the group:

for (const group in data) {
  for (const person of data[group]) {
    console.log(person.age)
  }
}

Comments

1

There is a much easier way:

const data = {
  g1 : [
    {"name" : "Jack", "age" : 32},
    {"name" : "Jill", "age" : 44}    
  ],
  g2 : [
    {"email" : "[email protected]", "city" : "Berlin", "age" : 14},
    {"email" : "[email protected]", "city" : "Stockholm", "age" : 22}
  ]
}

Object.values(data).forEach(group=>group.forEach(person=>console.log(person.age)));

Here's another version:

const data = {
  g1 : [
    {"name" : "Jack", "age" : 32},
    {"name" : "Jill", "age" : 44}    
  ],
  g2 : [
    {"email" : "[email protected]", "city" : "Berlin", "age" : 14},
    {"email" : "[email protected]", "city" : "Stockholm", "age" : 22}
  ]
}

Object.entries(data).forEach(
  group=>group[1].forEach(
    person=>console.log(
        group[0], 
        person.name ? person.name : person.email, 
        person.age)
  )
);

Object.entries return the list of properties and values in an object in an array, i.e., [[prop, val], [prop, val], ...].

So if you use forEach in it, the 0 index will be prop name, and 1 index will be value. This explains the

    Object.entries(data).forEach(
      group=>group[1]

part. So now we have the group name, and the val which is an array of persons. Then you can just iterate it with another forEach and get age property:

   [...]group[1].forEach(
           person=>console.log(person.age));

I just elaborated it a bit to get more relevant information with

   [...]group[1].forEach(
       person=>console.log(
           group[0], 
           person.name ? person.name : person.email, 
           person.age)
       )
    ) [...]

2 Comments

@ArthurVaïsse Better now ?
Yep! It is better this way. I still consider the for loop as way more explicit and simpler to tackle this simple problem though. I would only prefer functional style if I were needing some mapping or filtering on the dataset.
1

Let's try something clean and simple.

const data = {
  g1 : [
    {"name" : "Jack", "age" : 32},
    {"name" : "Jill", "age" : 44}    
  ],
  g2 : [
    {"email" : "[email protected]", "city" : "Berlin", "age" : 14},
    {"email" : "[email protected]", "city" : "Stockholm", "age" : 22}
  ]
}

consoleAllAges = obj => {
    for (i in obj) {
        const group = obj[i];
        group.forEach(person => {
            console.log(person.age);
        });
    }
}

Comments

1

many answers here advise using different methods but do not address your issue, or what was missing in your implementation for the ages to be printed.

what you were missing is accessing the values of the group, which you iterate.

try this:

for (const group in data) {
  for (const person of data[group]) {
    console.log(person.age)
  }
}

which will output

32
44
14
22

Comments

0

group is an An Array and not An Object. Instead try this

    for (const group in data) {
  for (const person of data[group]) {
    console.log(person.age)
  }
}  ​

1 Comment

there is no need for string interpolation
0

You can use Object.values(data) to return the two arrays g1 and g2 in one array. Then you want to use flat() for this array which will give you a single array with all the people inside. Finally you want to call map() to iterate over this array. Since p.age is implicitly returned to map() it will return an array with all the returned values.

console.log(Object.values(data).flat().map(p=>p.age));

Comments

0

Strings correction

  g1 : [
    {"name" : "Jack", "age" : 32},
    {"name" : "Jill", "age" : 44}    
  ],
 g2 : [
    {"email" : "[email protected]", "city" : "Berlin", "age" : 14},
    {"email" : "[email protected]", "city" : "Stockholm", "age" : 22}
  ]
}

change string inside

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.