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

Hash of Hash of Array Syntax help

by ZWcarp (Beadle)
on Jan 12, 2012 at 22:17 UTC ( #947658=perlquestion: print w/replies, xml ) Need Help??
ZWcarp has asked for the wisdom of the Perl Monks concerning the following question:

First off I'm still a noob, so thanks for putting up with what is probably a dumb question. Can someone explain to me what is going on in this
I think it is a Hash of a Hash of a Hash of an Array, inputing data from different elements of the array @r. But why does the array reference go at the front like that, what is it doing and how does it alter the way I might .. say print things down the line? I tried to find reading material by googling for this but wasn't able to find anything in this exact format. Any information or links or whatever would be very helpful.

Replies are listed 'Best First'.
Re: Hash of Hash of Array Syntax help
by GrandFather (Sage) on Jan 12, 2012 at 22:49 UTC

    I find it helps to add a little white space and remove the "extra" set of () that aren't required for push:

    push @{$genes{$r[0]}{$r[1]}{$r[2]}}, $r[3];

    genes must be a hash because it's being accessed using{} and it contains a series of nested hashes because there is a chain of {}{}: {$r[0]}{$r[1]}{$r[2]}. r is an array which you can tell because it's being accessed using []. The @{} wrapper around the genes access turns an array reference into an array (that's what the @ is about).

    So the whole thing pushes the fourth element of @r into an array stored in a hash stored in a hash stored in %genes.

    True laziness is hard work
      Ok thanks a ton.. so let me clarify to see if I get it... in this situation based on what you said :
      foreach my $key1 ( sort keys %genes ) { print "\t". scalar (keys %{$genes{$key1}}) . "\t"; foreach my $key2 ( sort keys %{$genes{$key1}} ) { etc....
      I am printing the number of hash keys at the $gene{$r4} level...... and the %{} is a wrapper that turns a hash reference into a hash? ( as opposed to above where its an @ ref into an @. So changing that reference to an actual hash allows me to see the true values of the keys ( or in this instance the number of them because of the scalar command) rather then seeing the hash reference? If the wrapper were not to be there and I tried to access a deeper level in the hash rather then just printing the values at that level, it wouldn't work because the values themselves don't store the information for the overall nested structure (thats what the refs are for) ..correct?
Re: Hash of Hash of Array Syntax help
by tobyink (Abbot) on Jan 12, 2012 at 22:53 UTC

    OK, there is an array @r somewhere in scope. It has at least four elements. For simplicity, let's assume...

    my @r = ('a', 'b', 'c', 'd');

    Thus your original code can be rewritten as:

    push @{ $genes{'a'}{'b'}{'c'} }, 'd';

    Which means that %genes is a hash; $genes{'a'} is one of the items in the hash, and the value of $genes{'a'} is itself a hashref. Similarly, the value of $genes{'a'}{'b'} is also a hashref, and $genes{'a'}{'b'}{'c'} is an arrayref.

    And here we're pushing 'd' onto the array referenced by $genes{'a'}{'b'}{'c'}.

    So overall, your code is pushing the value of $r[3] onto an array, which is referenced by the value corresponding to key $r[2] in a hash, which is referenced by the value corresponding to key $r[1] in a hash, which is referenced by $genes{ $r[0] } which itself is a single value from the hash %genes.

    You could say %gene is a hash of hashes of hashes of arrays, though of course when you have a tree structure like that, perhaps not all branches are symmetrical. If $r[0] took a different value, then perhaps we might consider %gene to be a hash of file handles.

Re: Hash of Hash of Array Syntax help
by ikegami (Pope) on Jan 12, 2012 at 23:37 UTC
    @{ $genes{$r[0]}{$r[1]}{$r[2]} }

    is short for

    @{ $genes{$r[0]}->{$r[1]}->{$r[2]} }

    which is equivalent to

    @{ ${ ${ $genes{$r[0]} }{$r[1]} }{$r[2]} }

    There are two notations for dereferencing.

    • The embedded* notation (${ $array }[4]) can be used to dereference anything that can be deferenced, but it's a bit clunky.

    • The arrow notation ($array->[4]) is cleaner, but it can only be used for some forms of dereferencing.

    There's no arrow equivalent for @{ $array }, so using push @{ ... }, $r[3] was necessary.

    * — I just made up that name. I don't know of any existing name for it.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://947658]
Approved by GrandFather
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (7)
As of 2017-01-23 05:19 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (190 votes). Check out past polls.