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

Hi folks, I've been having trouble referencing an array to the value pair of a hash.
The data that I have kind of looks like this:

ab mock 01 data1 data2 data3 data4
ab mock 02 data5 data6 data7 data8
ab mock 03 data9 data0 data3 data2

The third item (from the left) on each line is to be my key for the hash. But then as the value for the hash I want all the values on the line to be associated with that key. I've tried to split each element on the line into and array and then incorrectly tried to associate that with the hash but obviously that doesn't seem to be working and I don't know how to do it right :). Any help would be appreciated! Another question I would also have is how would I then get a particular array element for a particular key of the hash? Thanks.
here is part of the code:

open(PARMFILE, "<$parmfile") || die "unsuccessful open of input file $ +parmfile"; while (<PARMFILE>) { next if /^#/ || /^\s*$/; chomp; @temp=split(/\s+/,$_); $array_ref = \@temp; # confusion $dbparms{$temp[2]} = $array_ref; # here } close PARMFILE; foreach $item (sort keys %dbparms) { print "$item => $dbparms{$item} \n"; }

Replies are listed 'Best First'.
(bbfu) (reference to global variable) Re: associate that array with this hash?
by bbfu (Curate) on Sep 27, 2001 at 20:00 UTC

    The reason it's not working is because you're creating a reference to exactly the same variable each time (because @temp is global instead of lexical).

    What you should do, is change @temp to be a lexical variable, scoped to the body of the while loop. That way, a new lexical variable will be created each time, and the reference that you stored away in the hash will keep all the old lexical variables alive (but anonymous). Like so:

    open(PARMFILE, "< $parmfile") or die "unsuccessful open of input file $parmfile"; while (<PARMFILE>) { next if /^#/ || /^\s*$/; chomp; my @temp=split(/\s+/,$_); # Note the 'my' $dbparms{$temp[2]} = \@temp; } close PARMFILE; foreach $item (sort keys %dbparms) { print "$item => $dbparms{$item} \n"; }

    And that should get the effect you want.

    Update: I tested it, and it does work, although your print loop doesn't dereference the array-ref so you just get a bunch of lines like: '01 => ARRAY(0x1accdcc)'. Change the print loop to the following for a more useful output ;-)

    foreach $item (sort keys %dbparms) { $" = ','; print "$item => @{$dbparms{$item}} \n"; }

    bbfu
    Seasons don't fear The Reaper.
    Nor do the wind, the sun, and the rain.
    We can be like they are.

      still doesn't seem to work, the output looks like this
      01 => ARRAY(0x20038aa0) 02 => ARRAY(0x20038b30) 03 => ARRAY(0x20038b90)
      thanks

        See my update. Basically: the print is bad, the data is good.

        bbfu
        Seasons don't fear The Reaper.
        Nor do the wind, the sun, and the rain.
        We can be like they are.

Re: associate that array with this hash?
by davorg (Chancellor) on Sep 27, 2001 at 20:11 UTC

    Looks to me like the old "taking a reference to the same array many times" problem. Because @temp is a package variable, you'll get the same reference each time and end up storing multiple copies of the last record. Is that what you're seeing?

    Fixing it is easy. Either create a new @temp each time with my like this:

    while (<PARMFILE>) { next if /^#/ || /^\s*$/; chomp; my @temp=split(/\s+/,$_); $dbparms{$temp[2]} = \@temp; }

    or copy the array each time:

    while (<PARMFILE>) { next if /^#/ || /^\s*$/; chomp; @temp=split(/\s+/,$_); $dbparms{$temp[2]} = [@temp]; }

    See perldoc perldsc for more description of this problem.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you don't talk about Perl club."