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

Hello Monks
Thanks a million for taking a look at my code ....

I have a file in the form
id1 val1
id1 val2
id2 val1
id2 val3
id3 val2
id3 val3
id3 val4

I'm forming a HoA that associates the ids which are unique with their values that are not. I want a user to enter an id (or ids). The ids are then looked up in the hash and the array of values associated with each id is printed.

Okay so my code runs - it does hang but thats due to the silly size of the file. I get a very long list of
....
Q9ZZZ4 ARRAY(0xf4d641c)
Q9ZZZ5 ARRAY(0xf4d6464)
....
which is okay... I think. So I create my hash, I enter an id <STDIN> and the id is found or not depending on if its in the hash. So far so good. The problem is with printing the array of associated vals. I have tried a couple of methods.

The first method below but commented out - pints the first val only. print "$user: @{ $p2i{$user} }\n";

The second method prints the ref to the array .i.e. ARRAY(0xf4d4a88)

print "$user is in the hash. \n"; @user_array = split(/ /, $p2i{$user}); foreach (@user_array) { print "$_\n"; }
The full code is below. I think my problem is that I'm not dereferencing the array correctly....

#!/usr/bin/perl use strict; use warnings; my $file = "p2iextact.txt"; my %p2i; my @user_array; my $sp; my $ipr; my $key; my $user; # creates hash of arrays open(FILE, "p2iextact.txt") || die "can't open file"; while(<FILE>) { chomp; ($sp, $ipr) = split; if (exists $p2i{$sp}) { push @{$p2i{sp}}, $ipr; } else { $p2i{$sp}= [$ipr]; } } close FILE; # test to see if hash created correctly foreach $key (sort keys %p2i) { print "$key\t$p2i{$key}\n"; } print "Please enter an ID: "; chomp( $user = <STDIN>); # try to used uppercaes function to avoid errors $user = uc($user); #see if id is in the hash and print @vals if (exists $p2i{$user}) { print "$user is in the hash. \n";if (exists $p2i{$user}) { print "$user is in the hash. \n"; @user_array = split(/ /, $p2i{$user}); foreach (@user_array) { print "$_\n"; } # print "$user: @{ $p2i{$user} }\n"; # only retieves one value even when more than one #val even +if there are multiple } else { print "$user is not in the hash.\n"; } exit;

Cheers
Stalky

Replies are listed 'Best First'.
Re:de-ref an array from HoA
by davidj (Priest) on Jun 17, 2004 at 12:21 UTC
    I found 4 problems with your code:
    2 syntax errors
    1 logical error
    1 formatting for this site error

    syntax error #1:
    you have
    push @{$p2i{sp}}, $ipr; # $ missing for key reference
    when you should have
    push @{$p2i{$sp}}, $ipr;

    syntax error #2:
    you have
    print "$key\t$p2i{$key}\n";
    when you should have
    print "$key\t@ {$p2i{$key} }\n"; # need @ to dereference array

    logical error #1:
    your use of uc() for key lookups will return nothing because the hash keys, as entered from the text file, are all lowercase (at least in the sample you provided).

    formatting error #1:
    you have
    if (exists $p2i{$user}) { print "$user is in the hash. \n";if (exists $p2i{$user}) { print "$user is in the hash. \n";
    when you should have
    if (exists $p2i{$user}) { print "$user is in the hash. \n";


    I corrected the above and the code ran fine

    hope this helps,
    davidj
      Thanks to you all the code works now!

      Cheers
      Stalky
Re:
by periapt (Hermit) on Jun 17, 2004 at 11:59 UTC
    There are a couple of issues with your code

    In your first while loop, you have a bareword sp where you meant $sp. The effect of this would be to assign only one value to each key in the file. Second and subsequent values for a key would be assigned to $p2i{sp}.

    In your first foreach loop you try to print the value of $p2i{$key} which is simply a reference to the array you have stored the values in. You have to dereference this value into an array with @{$p2i{$key}}

    You have some duplicative code in your if(exists...) loop. You can print the values of the array in $p2i{$user} with the simple foreach loop.

    For more information on references, take a look at perldoc -m perlreftut and perldoc -m perlref
    while(<FILE>) { chomp; ($sp, $ipr) = split; if (exists $p2i{$sp}) { push @{$p2i{$sp}}, $ipr; # push @{$p2i{sp}}, $ipr; } else { $p2i{$sp}= [$ipr]; } } close FILE; # test to see if hash created correctly foreach $key (sort keys %p2i) { # print "$key\t$p2i{$key}\n"; print "$key\t@{$p2i{$key}}\n"; } if (exists $p2i{$user}) { # print "$user is in the hash. \n";if (exists $p2i{$user}) { print "$user is in the hash. \n"; # @user_array = split(/ /, $p2i{$user}); # @user_array = split(/ /, $p2i{$user}); # foreach (@user_array) { # print "$_\n"; # } foreach (@{$p2i{$user}}){ print "$_ "; } print "\n"; # print "$user: @{ $p2i{$user} }\n"; # only retieves one value even when more than one #val even if the +re are multiple # } } else { print "$user is not in the hash.\n"; } exit;

    PJ
    We are drowning in information and starving for knowledge - Rutherford D. Rogers
    What good is knowledge if you have to pull teeth to get it - anonymous
Re: de-ref an array from HoA
by pelagic (Priest) on Jun 17, 2004 at 11:18 UTC
    You should absolutely have a look at perldoc perlref !
    my @array = qw[aa bb cc dd ee ff gg]; my $r2a = \@array; foreach (@{$r2a}) { print "$_\n"; }

    pelagic