ebodine has asked for the wisdom of the Perl Monks concerning the following question:

I am having a problem accessing information in a hash of an array containing hashes & arrays. I don't really understand how it is done. I can access the array in the hash, but beyond that, I am in trouble.

The following is the array, basically the value of the key if I understand this correctly.

Volume: alpha: 0 512 1048576 1 HASH(0x8580988) ARRAY(0x8580958) HASH(0x8580eb0) -1 0 0 0 0 0 zfod 0

The following is the code that I have so far. Any ideas, suggestions would be greatly appreciated.

for my $vol_key ( keys %::Volume_Info ) { print "Volume: $vol_key\n"; foreach my $item ( @{ $::Volume_Info{$vol_key}} ) { if (ref($item) eq "ARRAY") { print "Array in Array item: $item\n"; } elsif (ref($item) eq "HASH") { print "Hash in Array: $item\n"; } else { print "Array Item: $item \n"; } } }

Replies are listed 'Best First'.
Re: A hash of an array containing hashes & arrays
by Bird (Pilgrim) on Aug 21, 2002 at 17:40 UTC
    Couple things... First, you don't want to use eq when checking the result of your ref() call, because it'll never match. The ref($item) will return a value like HASH(0x8580988), so you only want to see if it contains the string "HASH". Like so...
    if (ref($item) =~ /HASH/) {}
    Second, if you're trying to print out the actual values in the hash or array referenced in your top-level array, you're going to need to dereference them.
    print "Array in Array: ", @{$item}, "\n"; ... print "Hash in Array: ", %{$item}, "\n";
    ...and so you end up with something like...
    #!/usr/bin/perl -w use strict; $, = " "; my %Volume_Info = ( alpha => [ 0, 512, 1048576, 1, { one => 'first_hash' }, [ 'two', 'first_array' ], { three => 'second_hash' }, -1, 0, 0, 0, 0, 0, 'zfod', 0 ], beta => [ 1, 2, 3, { four => 'third_hash' }, 2, 1 ] ); for my $vol_key ( sort keys %Volume_Info ) { print "\nVolume: $vol_key\n"; foreach my $item ( @{ $Volume_Info{$vol_key}} ) { if (ref($item) =~ /ARRAY/) { print "Array in Array item: ", @{$item}, "\n"; } elsif (ref($item) =~ /HASH/) { print "Hash in Array: ", %{$item}, "\n"; } else { print "Array Item: $item \n"; } } }
    ...which produces...
    Volume: alpha Array Item: 0 Array Item: 512 Array Item: 1048576 Array Item: 1 Hash in Array: one first_hash Array in Array item: two first_array Hash in Array: three second_hash Array Item: -1 Array Item: 0 Array Item: 0 Array Item: 0 Array Item: 0 Array Item: 0 Array Item: zfod Array Item: 0 Volume: beta Array Item: 1 Array Item: 2 Array Item: 3 Hash in Array: four third_hash Array Item: 2 Array Item: 1
    Hope this helps.

    -Bird

    Update: Made my code a little more consistent across examples.

    Update 2: Silly me not reading up on ref before responding. :-} See comments by thelenm and Chmrr below.

      I questioned the "ref($item) eq " as well. But take a look at the ref function description in the Camel Book 3rd Ed. on pg. 773. It uses "eq" as well. I tried @{$item} & %{$item} and got the following:

      Volume: alpha
      Array Item: 0
      Array Item: 512
      Array Item: 1048576
      Array Item: 1
      Hash in Array: %{HASH(0x8580a24)}
      Array in Array item: ARRAY(0x840824c)
      Hash in Array: %{HASH(0x8580f4c)}
      Array Item: -1
      Array Item: 0
      Array Item: 0
      Array Item: 0
      Array Item: 0
      Array Item: 0
      Array Item: zfod
      Array Item: 0
      Array Item:

      --ERick
        You can test ref using eq. Try this, for example:
        perl -le '$foo{"bar"} = ["a","b"]; print ref $foo{"bar"}'
        ... prints "ARRAY". But if for some reason you're testing the stringification of an array reference (not the return value of ref), then you shouldn't use eq.

        What are you expecting to see in your output? Hashes are not interpolated into strings, but arrays are, so printing "Array in Array item: @$item" should print the array elements in $item. A clearer way would be a foreach loop or map, perhaps like this:

        if (ref $item eq 'ARRAY') { print "Array in Array item:\n"; foreach (@$item) { print " $_\n"; } } elsif (ref $item eq 'HASH') { print "Hash in Array item:\n"; foreach (keys %$item) { print " $_ -> $item->{$_}\n"; } } else { print "Array Item: $item\n"; }

        -- Mike

        --
        just,my${.02}

      Your comment about ref is not quite correct. If used on a blessed object, it will return the package the object has been blessed into. Otherwise, it will simply return one of the built-in types as strings, that is, one of qw/SCALAR ARRAY HASH CODE REF GLOB LVALUE/ Thus, use of eq in this case is actually correct. See perldoc -f ref for more information.

      perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'