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

Data structure is a double hash of array, followed by another hash.
I was just building a data structure to house record details of a file with many formats. I want these information readily accessable and be ready to 'unpack' when ready. The data is binary.
The first hash is for naming record format.
Second hash is for various record properties.
Third Array is for list of fields.
Fourth hash is for various field properties.
How do I get to the end of last hash in one breath?
As shown in result, I couldn't figure out the syntax to do it.
Snippet:
#!/usr/local/bin/perl use strict; use warnings; my (@tempd, %tempa); push @tempd, (nm=>'abc', sz=>'def'); $tempa{'a'}{'zeta'}=[@tempd]; print "array: ", join " ", @tempd, "\n"; my $tmp = $tempa{'a'}{'zeta'}; print "hash: ", $tempa{'a'}{'zeta'}, "\n"; print "hash: ", $$tmp[0], " ", $$tmp[1], "\n"; Result: array: nm abc sz def hash: ARRAY(0x40039370) hash: nm abc

Replies are listed 'Best First'.
Re: double hash, array, and hashed data structure
by mr_mischief (Monsignor) on Mar 12, 2008 at 22:38 UTC
    print "hash: ", join " " , @{ $tempa{'a'}{'zeta'} }, "\n";

    See perlref and perlreftut to really grok this.

    The issue is that you had a reference to an array that was still a reference. You need to deref that array to get at its contents.

Re: double hash, array, and hashed data structure
by almut (Canon) on Mar 12, 2008 at 22:49 UTC

    Not really sure, but your description sounds like you may have meant:

    push @tempd, { nm=>'abc', sz=>'def' };

    Note the braces (instead of the parentheses) — this pushes a hashref.

    Then, you could for example directly access the value 'abc' like this:

    $tempa{a}{zeta}[0]{nm}

      almut followed the same suggestion that I had.

      I'm not sure I understood what you're looking for; but here is a little program that shows a similar strategy to almut's...I think it is what you were looking for.

      #!/usr/bin/perl my %hash; my $rec_format_name = "foo"; my $rec_property = "color"; my $field_number = 3; my $field_property = "length"; $hash{$rec_format_name}{$rec_property}[$field_number]{$field_property} + = 7; my $value = $hash{$rec_format_name}{$rec_property}[$field_number]{$field_prop +erty}; print "\$rec_format_name = $rec_format_name\n"; print "\$rec_property = $rec_property\n"; print "\$field_number = $field_number\n"; print "\$field_property = $field_property\n"; print "-------------------------------------------\n"; print "\$value = $value\n"; exit(0);

      When run, here is the output:

      $rec_format_name = foo $rec_property = color $field_number = 3 $field_property = length ------------------------------------------- $value = 7

      This uses Perl's autovivication to instantiate the initial hash and all of its substructure. Perl takes care of all of the dereferencing for you...so you don't have use all of the embedded curly-braces. In the suggested references/tutorials that mr_mischief offered, it talks about the strategy of doing the dereferencing using the -> syntax and the rules for when you can ommit the ->'s...which allows the syntax that almut suggested and that I have used in the above little script.

      ack Albuquerque, NM
Re: double hash, array, and hashed data structure
by NetWallah (Canon) on Mar 12, 2008 at 23:32 UTC
    Taking almut's (++) solution one step further, you could avoid the @tempd array entirely, using either a regular hash-ref assignment (for a new segment of the hash), or a hash-slice assignment:
    # Using hash-ref assignment: $tempa{a}{zeta} = {nm=>'abc', sz=>'def'}; # Using Hash slice -- @{$tempa{a}{zeta}}{qw[nm sz]} = qw[abc def]; #Resulting structure: #= { # 'a' => { # 'zeta' => { # 'sz' => 'def', # 'nm' => 'abc' # } # } # };
    Data::Dumper is your friend, in viewing these structures.

         "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

      Thanks everybody, seems so easy once I saw the examples :)
      I am sure I will keep on kicking myself on the {} instead of ().
      Reply to NetWallah:
      The reason why I have to have tempd as a intermediate is due to XML parsing order. All fields come first from the way xml:twig returns, than the record details. Don't want to copy data once it is built, so the reference is made instead.
      Regards,
      Ben
Re: double hash, array, and hashed data structure
by repellent (Priest) on Mar 13, 2008 at 19:23 UTC
    When accessing deep-nested data structures, take no chances with autovivification. Make use of Data::Diver

    For example, fire up your Perl debugger:
    $ perl -de ''
    Then enter these lines:
    undef $ref exists $ref->{intervened}->{notvivified} # should not exist x $ref
    You'll see that $ref->{intervened} has been autovivified. Scary, isn't it? This also applies to dereferencing arrays.