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

Dear Monks,

I can find the key in hash bye using below code.

my %hash=("111"=>"one", "222"=>"two"); if (defined($hash{"111"})) { print "\nfound"; }

How can we find the value without using key. i.e. I need to find "one" value in hash.

Thanks
Kanishk

Replies are listed 'Best First'.
Re: grep value in hash
by davorg (Chancellor) on Feb 17, 2006 at 11:55 UTC

    Depends what exactly you need to do.

    If you just want to know if the value is in the has then you can use values.

    if (grep { $_ eq '111' } values %hash) { print 'found'; }

    If you want to know which key is associated with the value, you can use keys.

    foreach (keys %hash) { if ($hash{$_} eq '111') { print "Found at key $_"; last; } }

    Or each.

    while (my ($k, $v) = each %hash) { if ($v eq '111') { print "Found at key $k"; last; } }
    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      Alternately if this is something you need to do often build an inverted hash with the keys and values switched.

      my %hash_inverted; @hash_inverted{ values %hash } = keys %hash;

      Just remember that this won't be automagically updated so if you update %hash you'll need to also update %hash_inverted (and/or wrap them both up in an object and let that keep things updated for you when you use its accessors).

      Update: Good point below about duplicates, which also brings up the point that if your original hash has non-scalar values you may need something like Tie::RefHash for the inverted version.

        Another issue to be aware of is duplicate values. This can be handled by doing a bit more work with the inversion:

        my %hash_inverted; for (keys %hash) { my $value = $hash{$_}; push @{ $hash_inverted{$value} }, $_; }

        This way each value in the inverted hash will be an array reference, which contains all the keys that value corresponds to.

      Hi, can you please give me insight about the code

       grep { $_ eq '111' } values %hash

        The node you're responding to is over 14 years old! Sadly, its celebrated author (the famous davorg) hasn't visited us for more than two years and so is unlikely to respond. BTW, davorg, aka Dave Cross, is former head honcho of London.pm (around the time they sponsored a camel at London zoo), professional Perl trainer for over twenty years, and the author of at least four Perl books. Let's hope he visits us again soon.

        Meanwhile, I'll try to explain his masterful one-liner for you. You should read the immortal line:

        grep { $_ eq '111' } values %hash
        as a "pipeline" from right to left. The call to values %hash returns a list of all values in the hash (see values). The grep function evaluates the { $_ eq '111' } code block for each element of this list (locally setting $_ to each element), returning a list consisting of those elements for which the expression evaluated to true. That is, it returns a list of all values in %hash which have the exact value 111.

        Note that hashes have unique keys but their values are not unique, so the list returned by this expression may have more than one element; the above expression will only tell you how many times the value 111 appears in the hash but will not tell you the keys of the hash with that value -- for that, you would need to iterate through the keys of the hash instead, checking each value in turn (as the legend davorg did in his second code snippet, using the keys function).

        Now I've answered your question, you gotta tell me why you were asking a question about such an ancient node (I won't be able to sleep tonight not knowing).

Re: grep value in hash
by Praveen (Friar) on Feb 20, 2006 at 12:39 UTC
    Try this
    @ary = grep{/one/} values %hash; print "found", if(scalar @ary > 0);

      I can't see how scalar @art could ever return a negative number, so your >0 check is probably overkill.

      print "found" if scalar @ary;

      But, given that grep in scalar contents returns the number of matches, I'd probably skip the temporary value and use:

      print "found" if grep { /one/ } values %hash;

      Oh, and using a regex to match a fixed string is inefficient.

      print "found" if grep { $_ eq 'one' } values %hash;

      And we're pretty much back to my first solution :)

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

      "The first rule of Perl club is you do not talk about Perl club."
      -- Chip Salzenberg