How do I reference a Perl hash in an array in a hash?

TallGuy picture TallGuy · Jan 3, 2010 · Viewed 20k times · Source

This is the code snippet I am working with:

my %photo_details = (
 'black_cat' => (
  ('size' => '1600x1200', 'position' => -25),
  ('size' => '1280x1024', 'position' =>  25),
  ('size' =>   '800x600', 'position' =>   0),
 ),
 'race_car' => (
  ('size' => '1600x1200', 'position' =>  10),
  ('size' =>   '800x600', 'position' =>   5),
 ),
);

my $photo = 'black_cat';

foreach my $photo_detail ($photo_details{$photo})
{
 my $size     = $photo_detail{'size'};
 my $position = $photo_detail{'position'};

 print ("size = $size, position = $position\n");
}

What I am expecting to get is:

size = 1600x1200, position = -25

size = 1280x1024, position = 25

size = 800x600, position = 0

What I do get is:

Use of uninitialized value $size in concatenation (.) or string at C:\Test.pl line 23.

Use of uninitialized value $position in concatenation (.) or string at C:\Test.pl line 23.

size = , position =

The foreach statement is clearly wrong as not only are there no values for $size and $position, it has only gone through the loop once instead of three times. I have tried all sorts of variants of variable prefixes and found none that work.

What am I doing wrong?

Answer

Ether picture Ether · Jan 3, 2010

First of all, always start every script or module with:

use strict;
use warnings;

You will get more warning messages and sooner, which greatly helps debugging.

I cannot duplicate your error: when I put that code into a file and run it with no additional flags, I get: size = , position =. There is no $size variable in the code you printed, so the error message does not match.

Nevertheless, you are declaring your data structures incorrectly. Hashes and arrays can only contain scalar values, not lists: so if you want to nest an array or a hash, you need to make it a reference. See perldoc perldata, perldoc perldsc and perldoc perlreftut for more about data structures and references.

my %photo_details = (
    black_cat => [
        { size => '1600x1200', position => -25 },
        { size => '1280x1024', position =>  25 },
        { size => '800x600', position => 0 },
    ],
    race_car => [
        { size => '1600x1200', position =>  10 },
        { size => '800x600', position =>   5 },
    ],  
);

foreach my $photo_detail (@{$photo_details{black_cat}})
{
    my $size     = $photo_detail->{size};
    my $position = $photo_detail->{position};

    print ("size = $size, position = $position\n");
}