tsiro
tsiro

Reputation: 2403

iterate through nested hash perl

i have the following perl format:

  my $categories = {
          category =>  {
                         {  id    =>  1,
                            name  =>  "pizza"},
                         {  id    =>  2,
                            name  =>  "pizza special"},
                         {  id    =>  3,
                            name  =>  "pasta"},
                         {  id    =>  4,
                            name  =>  "burgers"},
                         {  id    =>  5,
                            name  =>  "club sandwich"}
                      }
};

what i would like to achieve is to iterate through the above perl format and get the id and name for each hash inside category.. what i have tried to do is:

foreach ( $categories->{category} ) {
              $Response->write(qq[
                      <div class="row text-center">
                          <div class="col-xs-4">$_->{id}</div>
                          <div class="col-xs-8">$_->{name}</div>
                      </div>
              ]);
        } 

but this is not producing any results on screen..can anyone help?

Upvotes: 0

Views: 1120

Answers (3)

simbabque
simbabque

Reputation: 54381

The data structure you have listed will not work the way you intend. It's either a copy/paste error when you created your question, or you made that manually and made a mistake.

  my $categories = {
          category =>  {
                         {  id    =>  1,
                            name  =>  "pizza"},
                         {  id    =>  2,
                            name  =>  "pizza special"},
                         {  id    =>  3,
                            name  =>  "pasta"},
                         {  id    =>  4,
                            name  =>  "burgers"},
                         {  id    =>  5,
                            name  =>  "club sandwich"}
                      }
};

use Data::Printer;
p $categories;

__END__

Odd number of elements in anonymous hash at /home/foo/code/scratch.pl line 438.
\ {
    category   {
        HASH(0x1aa6148)   {
            id     2,
            name   "pizza special"
        },
        HASH(0x1ab9920)   {
            id     4,
            name   "burgers"
        },
        HASH(0x1acfbd8)   undef
    }
}

As you can see, you are using hash references as keys inside of your hash reference.

use strict;
use warnings;
my $categories = {
    category =>  {
        {  id    =>  1, name  =>  "pizza"}, # key
        {  id    =>  2, name  =>  "pizza special"}, # value
        {  id    =>  3, name  =>  "pasta"}, # key
        {  id    =>  4, name  =>  "burgers"}, # value
        {  id    =>  5, name  =>  "club sandwich"} # key
        # BOOM! Odd number of elements
    }
};

That's probably not what you intended.

What you need to do instead is use an array reference for the list of foods.

my $categories = {
    category =>  [
        {  id    =>  1, name  =>  "pizza"},
        {  id    =>  2, name  =>  "pizza special"},
        {  id    =>  3, name  =>  "pasta"},
        {  id    =>  4, name  =>  "burgers"},
        {  id    =>  5, name  =>  "club sandwich"}
    ]
};

Now you can use this code to create your output. I replaced your object method call with a simple print for demonstration's sake.

foreach my $category ( @{ $categories->{category} } ) {
    print <<"HTML";
<div class="row text-center">
    <div class="col-xs-4">$category->{id}</div>
    <div class="col-xs-8">$category->{name}</div>
</div>
HTML
}

Because you now have an array reference, you need to dereference it with the @{ ... } syntax.

See perlref and perlreftut for more information on how references work in Perl.

Upvotes: 2

Sobrique
Sobrique

Reputation: 53508

First off - your data structure is wrong. It should either be:

#!/usr/bin/env perl

use strict;
use warnings;
my $categories = {
    category => [
        {   id   => 1,
            name => "pizza"
        },
        {   id   => 2,
            name => "pizza special"
        },
        {   id   => 3,
            name => "pasta"
        },
        {   id   => 4,
            name => "burgers"
        },
        {   id   => 5,
            name => "club sandwich"
        }
    ]
};

foreach my $hash_ref ( @{ $categories->{category} } ) {
    print qq[
                      <div class="row text-center">
                          <div class="col-xs-4">$hash_ref->{id}</div>
                          <div class="col-xs-8">$hash_ref->{name}</div>
                      </div>
              ];
}

Or:

my $categories = {
    category => {
        1 => "pizza",
        2 => "pizza special",
        3 => "pasta",
        4 => "burgers",
        5 => "club sandwich",
    }
};

foreach my $key (  sort keys %{$categories->{category}} ) { 
    print qq[
                      <div class="row text-center">
                          <div class="col-xs-4">$key</div>
                          <div class="col-xs-8">$categories->{category}->{$key}</div>
                      </div>
              ];
}

Turning on use strict; and use warnings; would have let you know:

Odd number of elements in anonymous hash at line 5.

Upvotes: 1

Hunter McMillen
Hunter McMillen

Reputation: 61550

You have built your Hash incorrectly, if you examine the Hash with Data::Dumper you will see this:

my $categories = {
   category => {
      {  id   => 1,
         name => "pizza"
      },
      {  id   => 2,
         name => "pizza special"
      },
      {  id   => 3,
         name => "pasta"
      },
      {  id   => 4,
         name => "burgers"
      },
      {  id   => 5,
         name => "club sandwich"
      }
   }
};
use Data::Dumper;
print Dumper $categories;

$VAR1 = {
          'category' => {
                          'HASH(0x7ff7746d3850)' => {
                                                      'name' => 'burgers',
                                                      'id' => 4
                                                    },
                          'HASH(0x7ff7746e1bc8)' => undef,
                          'HASH(0x7ff7746bee18)' => {
                                                      'name' => 'pizza special',
                                                      'id' => 2
                                                    }
                        }
        };

As you can see, since you did not provide a key for the inner Hash, it used the stringified value of the previous Hash as the key. I think you likely meant to make $categories->{category} and arrayref which would look like this:

my $categories = {
   category => [
      {  id   => 1,
         name => "pizza"
      },
      {  id   => 2,
         name => "pizza special"
      },
      {  id   => 3,
         name => "pasta"
      },
      {  id   => 4,
         name => "burgers"
      },
      {  id   => 5,
         name => "club sandwich"
      },
   ],
};

and could be iterated over like this:

foreach my $elem ( @{ $categories->{category} } ) {
   my ($id, $name) = map { $elem->{$_} } qw(id name);
   ...
}

Upvotes: 1

Related Questions