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

Hi Monks,

I am trying to create a hash of arrays, unsuccessfully! I have really almost copied my code from the camel book, but nothing seems to work for me. Is there anyone out there with HoA experience on Perl 5.8.0? I know that answer already.

use vars qw(%HoA); ## increment the sequencer. $HoA{sequence} = 0 unless exists $HoA{sequence}; my $i = ++$HoA{sequence}; $HoA{test} = [ "aaa", "bbb", "ccc" ]; print ("HoA test $i: " . $HoA{test} ."\n" ); print ("HoA test $i: " . $HoA{test}->[0] ."\n" ); print ("HoA test $i: " . @{ $HoA{test} } ."\n" );
Here is the output:
HoA test 11: ARRAY(0x87070a0) HoA test 11: HoA test 11:
Thanks in advance.

20030321 Edit by Corion: Fixed trailing open PRE tag, changed PRE tags to CODE

Replies are listed 'Best First'.
Re: Hash of Arrays
by robartes (Priest) on Mar 21, 2003 at 09:39 UTC
    When I run your code, it seems to work as expected:
    HoA test 1: ARRAY(0x8111b78) HoA test 1: aaa HoA test 1: 3
    You are, respectively, printing the array reference itself, the first element of the array and the array in scalar context, which produces the number of elements in the array.

    FYI, here are some general ways of manipulating HoA's:

    # Initialisation my %HoA = ( 'camel' => [ 'flea', 'bug-ridden', 'brown' ], 'flea' => [ 'camel-loving', 'bug', 'too tiny to tell' ] ); # Adding arrays: $HoA{'frog'}= [ 'tadpole', 'no bugs', 'green' ]; # Getting element of an array print "A camel is: ".$HoA{'camel'}->[2];
    A very useful module in this regard is Data::Dumper. You can use it to inspect the structure of your HoA:
    # HoA from above use Data::Dumper; print Dumper(\%HoA);
    Results in:
    $VAR1 = { 'flea' => [ 'camel-loving', 'bug', 'too tiny to tell' ], 'camel' => [ 'flea', 'bug-ridden', 'brown' ], 'frog' => [ 'tadpole', 'no bugs', 'green' ] };
    For more information, I recommend perldata, perlref and perldsc, all included in the standard Perl distribution.

    CU
    Robartes-

Re: Hash of Arrays
by Corion (Patriarch) on Mar 21, 2003 at 09:37 UTC

    I'm not sure about your code - either the code is incomplete or the results you posted are not the actual results. Here is what I get :

    D:\DATA\Projekte>type test.pl use strict; use vars qw(%HoA); ## increment the sequencer. $HoA{sequence} = 0 unless exists $HoA{sequence}; my $i = ++$HoA{sequence}; $HoA{test} = [ "aaa", "bbb", "ccc" ]; print ("HoA test $i: " . $HoA{test} ."\n" ); print ("HoA test $i: " . $HoA{test}->[0] ."\n" ); print ("HoA test $i: " . @{ $HoA{test} } ."\n" ); D:\DATA\Projekte>perl -w test.pl HoA test 1: ARRAY(0x1b9f0bc) HoA test 1: aaa HoA test 1: 3

    Your code shows HoA test 11, where I have HoA test 1 - either your sequence gets set earlier, or your results don't result from the code you showed. From the results you posted, I'd guess that the code that produced these results simply had an empty array.

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
Re: Hash of Arrays
by tekkie (Beadle) on Mar 21, 2003 at 14:39 UTC
    I agree with Corion that the code is probably incomplete, there is no way for $i to be set to "11" as you show in your output based on this code.

    I can't really make heads or tails of what you're trying to do with the 'sequence' key in general. Since you set the 'sequence' value to itself if it's there, or to zero if it's not, $i would always be 1 since the sequence value is never predefined. The only impact of those two lines above is setting $i to 1, you mine as well just use:
    my $i = 0;

    Please post the rest of this code so we can help further (and also you've got me somewhat intrigued as to what you're playing with here)
Re: Hash of Arrays
by Lhamo Latso (Scribe) on Mar 21, 2003 at 17:19 UTC
    Thanks for input, and sorry for the delay. I needed some sleep. Your comments have helped me tremendously. Besides not respecting the difference between scalar and list context, my hash was being tied to a DB_File dbm. After commenting the tie operation, the results are in line with everyone else.

    But now back to DB_File. Do I need to use a different module for complex data structures? Like maybe MLDBM? My original thought was that DB_File could handle it!???

    Here is the code that works for me, but without any hash tie:

    ## increment the sequencer. $HoA{sequence} = 0 unless exists $HoA{sequence}; my $i = ++$HoA{sequence}; print ("HoA sequence: $HoA{sequence} \n"); my $date = strftime('%d-%b-%Y %R',localtime); $HoA{$i} = [ ($date), map {escape(param($_))} (@FIELDS) ]; print ("HoA newvalue $i: $HoA{$i} \n" ); print ("HoA newvalue $i: $HoA{$i}[0] \n" ); print ("HoA newvalue $i: $HoA{$i}[1] \n" ); print ("HoA newvalue $i: $HoA{$i}[2] \n" ); print ("HoA newvalue $i: @{ $HoA{$i} } \n" ); print ("HoA newvalue $i: " . @{ $HoA{$i} } ."\n" ); $HoA{test} = [ "aaa", "bbb", "ccc" ]; print ("HoA test $i: " . $HoA{test} ."\n" ); print ("HoA test $i: " . $HoA{test}[0] ."\n" ); print ("HoA test $i: " . $HoA{test}[1] ."\n" ); print ("HoA test $i: " . $HoA{test}[2] ."\n" ); print ("HoA test $i: @{ $HoA{test} } \n" ); # returns list print ("HoA test $i: " . @{ $HoA{test} } ."\n" ); # returns count

    My plans for the $HoA{sequence} was to use it for saving the last sequence number. It would be a way to know where to insert the next node. Alla Oracle sequence. It seems silly to use a number as a hash key, but I want to tie the hash to a dbm. I could use an Array of Arrays, but is that tie-able?

    Update After more reading, I am now flattening the array before putting it in a tied hash. I used join and split for this. Here is more code; this works for me:

    sub write_guestbook { unless (TieLock($GUESTBOOKFILE, 1)) { print strong('Sorry, an error occurred: unable to open ' . $GU +ESTBOOKFILE),p(); return; } ## increment the sequencer. $HoA{sequence} = 0 unless exists $HoA{sequence}; my $i = ++$HoA{sequence}; my $date = strftime('%d-%b-%Y %R',localtime); $HoA{$i} = join(">", ($date), map {escape(param($_)) ."&nbsp;} (@F +IELDS) ); unTieLock($GUESTBOOKFILE); return( "Thank you <b>". param('First_Name') ."</b>, for signing the guestbook."); } sub view_guestbook { my $guestbook; my @rows; unless (TieLock($GUESTBOOKFILE, 0)) { print strong('Sorry, an error occurred: unable to open ' . $GU +ESTBOOKFILE),p(); return; } for my $addr (sort keys %HoA) { next if $addr eq "sequence"; my @data = map {unescape($_)} split( ">", $HoA{$addr} ); unshift @rows, td(\@data); } unshift @rows, th(['Entry Date',@FIELDS]); $guestbook .= p( table({-border=>'1', -hspace=>'5', -cellspacing=>'1', -cellpadding=>'4'}, TR(\@rows))); unTieLock($GUESTBOOKFILE); return ($guestbook); }