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

Dear monks, I have an array of ids that may or may not be present in a hash. For each id in the array, I want to print the id in consecutive order, but then print some extra info if it is found in the hash.

I have got my code working so that if the id is present it prints the correct information. However, when I print the values not in the hash, it just prints out all values again ( so in my printed list i get duplicates if a value is present in the hash).

How can I alter my code to print each id only once? Should the elsif bit not pick up everything not in the hash?

Thanks!

for (my $i=0; $i<@ids; $i++) { my $q; while ( my ($key, $value) = each(%hash) ) { #print "$key =>$value\n"; if ($ids[$i] eq $key) { print "$key => $value => $extra[$i]\n"; } #if ($ids[$i] ne $key) { elsif ($ids[$i] ne $key) { $q = "$ids[$i]\t $extra[$i]\n"; } } # PROBLEM IS HERE: IT IS PRINTING ONE OF EACH VALUE, NOT JUST +THOSE THAT AREN'T IN THE HASH print "$q"; }

Replies are listed 'Best First'.
Re: searching for values in hashes
by blazar (Canon) on Aug 05, 2005 at 09:51 UTC
    If I understand correctly your question, which I'm not sure of, you may be simply after (untested:
    for (0..$#ids) { my $id=$ids[$_]; print exists $hash{$id} ? "$id => $hash{$id} => $extra[$_]\n" : "$id\t$extra[$_]\n"; }
    Depending on your real needs s/exists/defined/, or even just s/exists//.

    Two cmts about your code:

    • two strings are either equal or not, so it is pointless to first test with eq and then with ne in an elsif clause,
    • avoid C-style for loops where possible, as Perl-style ones are more efficient and generally yield clearer code. (See also yesterday's Re: RFC: "Best Practices" code review section.)
    Also, here you need to traverse two arrays in parallel: it's a situation where Perl6's zip would come handy. But you may choose your data structures more efficiently instead: if @ids where an AoA containing the extra information too, then the above code may look (more clearly IMHO) like
    for (@ids) { my ($id,$extra)=@$_; print exists $hash{$id} ? "$id => $hash{$id} => $extra\n" : "$id\t$extra\n"; }
Re: searching for values in hashes
by aukjan (Friar) on Aug 05, 2005 at 09:32 UTC
    You might be looking for this (untested):
    for my $i ( 0 .. $#ids ){ if ( defined $hash{$ids[$i]} ){ print "$ids[$i] => ", $hash{$ids[$i]}, " => ", $extra[$i], "\n"; } else { print $ids[$i],"\t ",$extra[$i],"\n"; } }
Re: searching for values in hashes
by inman (Curate) on Aug 05, 2005 at 10:23 UTC
    You need to do two things.
    1. Iterate over the array using foreach. This avoids counting the index of the array when you aren't using it.
    2. Use the exists function to test whether a value exists in the hash

    The following illustrates this

    #! /usr/bin/perl use strict; use warnings; my @array = qw (one two three four five); my %hash = (one => 'Extra information for one', two => 'Extra information for two'); foreach my $id (@array) { if (exists $hash{$id}) { print "ID: $id has extra info: $hash{$id}\n"; } else { print "ID: $id has no extra info\n"; } }
      This was my first thought too, but this does not give the OP an index of the array to get the information directly from @extra (at least not that I know of). You would need an extra counter to keep track of the array index to accomplish this.