Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

Array of Hashes in subroutines.

by jlnh (Novice)
on Sep 18, 2010 at 16:15 UTC ( #860644=perlquestion: print w/replies, xml ) Need Help??
jlnh has asked for the wisdom of the Perl Monks concerning the following question:

HI everyone,
I have two problems to pass an array of hashes and I can't find out how to solve them.
#!/usr/bin/perl use strict; sub display(\%) { my $i; my @ref01 = shift; foreach $i (sort keys (%{$ref01[0]})) { print "$i: ${$ref01[0]}{$i} ${$ref01[1]}{$i} ${$ref01[2]}{$i}\n"; } } my (%hash1, $j, $z); $hash1{'fruit'} = ['apple', 'orange', 'plum']; $hash1{'vegetable'} = ['leek', 'carrot', 'peas']; $z = display (%hash1); foreach $j (sort keys (%hash1)) { print "$j: $hash1{$j}[0] $hash1{$j}[1] $hash1{$j}[2]\n"; * }
The output:
fruit: ARRAY(0x8775818) vegetable: ARRAY(0x878fea8) fruit: apple orange plum vegetable: leek carrot peas
Obviously, the array is incomplete and I can't dereference it. It would be great if someone could be able to modify that script.
Thank you for your help and your patience.

Replies are listed 'Best First'.
Re: Array of Hashes in subroutines.
by lima1 (Curate) on Sep 18, 2010 at 16:33 UTC
    You almost had it. Just pass a reference to the hash to your function with \%hash. You can access the elements without dereferencing with the -> operator.
    #!/usr/bin/perl use strict; sub display { my $ref01 = shift; foreach my $key (sort keys %{$ref01}) { print "$key: $ref01->{$key}[0] $ref01->{$key}[1] $ref01->{$key +}[2]\n"; } } my %hash1; $hash1{'fruit'} = ['apple', 'orange', 'plum']; $hash1{'vegetable'} = ['leek', 'carrot', 'peas']; display (\%hash1); foreach my $j (sort keys %hash1) { print "$j: $hash1{$j}[0] $hash1{$j}[1] $hash1{$j}[2]\n"; }
      Thank you so much for your help!
      I was desesperate.
        Hi Jean,

        Try out the following. It should work
        #! /usr/bin/perl use strict; use warnings; sub display { my $ref = shift; foreach my $key (sort keys %{$ref}) { print "$key = ["; foreach my $key1 (@{$ref->{$key}}) { print "$key1,"; } print "]\n"; } } my %hash1; $hash1{'frog'} = ['jumps','swims','slimy']; $hash1{'dog'} = ['barks','swims','hairy']; display(\%hash1);

        As someone had mentioned the module "Data Dumper" is really helpful. Even i am still learning and its really fun playing around with these references and derefences until you figure out what is happening. :)
        Hope it helped
Re: Array of Hashes in subroutines.
by oko1 (Deacon) on Sep 18, 2010 at 18:22 UTC

    Not that it'll make a difference here, but you should always enable warnings in your code - either via '-w' in the shebang, or 'use warnings' right below it. It'll save you lots of grief.

    As to your code - whenever you see that 'ARRAY(0xDEADBEEF)' output that you didn't expect, it's a sure sign that you forgot to dereference the variable you're trying to print. If that variable is something simple, like '$x', and you know that it's supposed to be an array, just stick an '@' sigil in front of it - @$x - and Perl will do the right thing. When it's more complex than that - say, $x is a pointer to an anonymous list and you want the first element - then use the IDO ("little arrow") syntax, '$x->[0]'. Last of all, when it's some ungodly mess that you don't even feel like figuring out - e.g., '($bar->(qw/fiddle glop/))[1][9]', and you want to get at the underlying array, just wrap the whole thing in curly braces and treat it like an array name. I.e.,

    print @{($bar->(qw/fiddle glop/))[1][9]}; # Print the whole list print ${($bar->(qw/fiddle glop/))[1][9]}[3]; # Print the 4th element print ${$x}[0]; # You can even use it i +nstead of the IDO - but it's kinda ugly :)

    'HASH(0xC0FFEE)' or whatever is pretty similar; obviously, you'd use '%' for the sigil and '{}' for the subscripts. For more about dereferencing, see perldoc perlref.

    As to the script itself, try this:

    #!/usr/bin/perl -w use strict; sub display { my $ref = shift; for my $k (sort keys %$ref){ print "$k: @{$ref->{$k}}\n"; } } my %hash1; $hash1{fruit} = [ qw/apple orange plum/ ]; $hash1{vegetable} = [ qw/leek carrot peas/ ]; display (\%hash1); for my $k (sort keys %hash1){ print "$k: @{$hash1{$k}}\n"; }

    "Language shapes the way we think, and determines what we can think about."
    -- B. L. Whorf
      Not that it'll make a difference here, but you should always enable warnings in your code ...

      Actually, it could have made a big difference, at least in the OPed code, had jlnh been aware of the significance of warnings.

      In that code, the statement
          my @ref01 = shift;
      creates and initializes an array that has (and can have) only one element upon initialization. The statement
          print "$i: ${$ref01[0]}{$i} ${$ref01[1]}{$i} ${$ref01[2]}{$i}\n";
      then tries to access non-existent elements at indices 1 and 2 ($ref01[1] and $ref01[2]) of that array, yielding undefined values to print. This would have produced a slew of warnings, had they been enabled, that might have directed jlnh to the essential problem (of many).

      Also: See the Data Structures Cookbook perldsc.

Re: Array of Hashes in subroutines.
by toolic (Bishop) on Sep 18, 2010 at 21:18 UTC
    Here is another handy link: References quick reference

    If all you're trying to do is display your data structure, Data::Dumper is a convenient way to do it:

    use strict; use warnings; use Data::Dumper; my %hash1; $hash1{'fruit'} = ['apple', 'orange', 'plum']; $hash1{'vegetable'} = ['leek', 'carrot', 'peas']; print Dumper(\%hash1); __END__ $VAR1 = { 'fruit' => [ 'apple', 'orange', 'plum' ], 'vegetable' => [ 'leek', 'carrot', 'peas' ] };
Re: Array of Hashes in subroutines.
by suhailck (Friar) on Sep 18, 2010 at 17:06 UTC
    You can write the line

     print "$j: $hash1{$j}[0] $hash1{$j}[1] $hash1{$j}[2]\n";


    print "$j: @{$hash1{$j}}\n";

Re: Array of Hashes in subroutines.
by biohisham (Priest) on Sep 19, 2010 at 07:17 UTC
    In the context of your code, @ref01 is better written as $ref01.

    You can make use of the flexibility of referencing and dereferencing to re-write

    foreach $i (sort keys (%{$ref01[0]})) { print "$i: ${$ref01[0]}{$i} ${$ref01[1]}{$i} ${$ref01[2]}{$i}\n"; }
    in a briefer and yet robust way. you don't want to index a hundred-element array manually now, do you?
    foreach $i (sort keys (%{$ref01})) { print "$i: @{$ref01->{$i}}\n"; }
    An interesting documentation page is perlcheat at You can access the same from your command console, type perldoc perlcheat.

    Best of luck and have a nice perl journey ..

    Excellence is an Endeavor of Persistence. A Year-Old Monk :D .

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://860644]
Approved by lima1
[LanX]: hmm aproval doesn't stick after move? Or was it a race condition
[Corion]: I think you need at least one reload after moving before you can approve in the correct section
[GotToBTru]: it was approved . but isnt now
[GotToBTru]: ah nevermind .. i was looking at one of 2
[GotToBTru]: SOPW version still shows approved by choroba

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (9)
As of 2017-01-16 15:13 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (151 votes). Check out past polls.