Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

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.
Jean-Louis

Comment on Array of Hashes in subroutines.
Select or Download Code
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 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";

    as

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

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 (Chancellor) 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 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 http://perldoc.perl.org. 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?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://860644]
Approved by lima1
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2014-07-22 08:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (106 votes), past polls