Dirk J. Faber
Dirk J. Faber

Reputation: 4701

looping over objects in an array inside an object (with for...in)

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.

Upvotes: 0

Views: 111

Answers (8)

Mr.
Mr.

Reputation: 10102

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

Upvotes: 1

user12603016
user12603016

Reputation:

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);
        });
    }
}

Upvotes: 1

Cak Sup
Cak Sup

Reputation: 17

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

Upvotes: 0

fubar
fubar

Reputation: 383

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));

Upvotes: 0

Saurav
Saurav

Reputation: 197

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)
  }
}  ​

Upvotes: 0

Nelson Teixeira
Nelson Teixeira

Reputation: 6572

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)
       )
    ) [...]

Upvotes: 1

Yousername
Yousername

Reputation: 1012

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());

Upvotes: 3

Alexander van Oostenrijk
Alexander van Oostenrijk

Reputation: 4764

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)
  }
}

Upvotes: 2

Related Questions