How to test if a value exist in a hash?

后端 未结 6 1320
-上瘾入骨i
-上瘾入骨i 2020-12-08 12:20

Let\'s say I have this

#!/usr/bin/perl

%x = (\'a\' => 1, \'b\' => 2, \'c\' => 3);

and I would like to know if the value 2 is a ha

相关标签:
6条回答
  • 2020-12-08 12:33

    Fundamentally, a hash is a data structure optimized for solving the converse question, knowing whether the key 2 is present. But it's hard to judge without knowing, so let's assume that won't change.

    Possibilities presented here will depend on:

    • how often you need to do it
    • how dynamic the hash is

    One-time op

    • grep $_==2, values %x (also spelled grep {$_==1} values %x) will return a list of as many 2s as are present in the hash, or, in scalar context, the number of matches. Evaluated as a boolean in a condition, it yields just what you want.
      grep works on versions of Perl as old as I can remember.
    • use List::Util qw(first); first {$_==2} values %x returns only the first match, undef if none. That makes it faster, as it will short-circuit (stop examining elements) as soon as it succeeds. This isn't a problem for 2, but take care that the returned element doesn't necessarily evaluate to boolean true. Use defined in those cases.
      List::Util is a part of the Perl core since 5.8.
    • use List::MoreUtils qw(any); any {$_==2} values %x returns exactly the information you requested as a boolean, and exhibits the short-circuiting behavior.
      List::MoreUtils is available from CPAN.
    • 2 ~~ [values %x] returns exactly the information you requested as a boolean, and exhibits the short-circuiting behavior.
      Smart matching is available in Perl since 5.10.

    Repeated op, static hash

    Construct a hash that maps values to keys, and use that one as a natural hash to test key existence.

    my %r = reverse %x;
    if ( exists $r{2} ) { ... }
    

    Repeated op, dynamic hash

    Use a reverse lookup as above. You'll need to keep it up to date, which is left as an exercise to the reader/editor. (hint: value collisions are tricky)

    0 讨论(0)
  • 2020-12-08 12:33

    Where $count would be the result:

    my $count = grep { $_ == 2 } values %x;
    

    This will not only show you if it's a value in the hash, but how many times it occurs as a value. Alternatively you can do it like this as well:

    my $count = grep {/2/} values %x;
    
    0 讨论(0)
  • 2020-12-08 12:43
    my %reverse = reverse %x;
    if( defined( $reverse{2} ) ) {
      print "2 is a value in the hash!\n";
    }
    

    If you want to find out the keys for which the value is 2:

    foreach my $key ( keys %x ) {
      print "2 is the value for $key\n" if $x{$key} == 2;
    }
    
    0 讨论(0)
  • 2020-12-08 12:45

    grep and values

    my %x = ('a' => 1, 'b' => 2, 'c' => 3); 
    
    if (grep { $_ == 2 } values %x ) {
        print "2 is in hash\n";
    }
    else {
        print "2 is not in hash\n";
    }
    

    See also: perldoc -q hash

    0 讨论(0)
  • 2020-12-08 12:53

    Everyone's answer so far was not performance-driven. While the smart-match (~~) solution short circuits (e.g. stops searching when something is found), the grep ones do not.

    Therefore, here's a solution which may have better performance for Perl before 5.10 that doesn't have smart match operator:

    use List::MoreUtils qw(any);
    if (any { $_ == 2 } values %x) {
        print "Found!\n";
    }
    

    Please note that this is just a specific example of searching in a list (values %x) in this case and as such, if you care about performance, the standard performance analysis of searching in a list apply as discussed in detail in this answer

    0 讨论(0)
  • 2020-12-08 12:57

    Shorter answer using smart match (Perl version 5.10 or later):

    print 2 ~~ [values %x];
    
    0 讨论(0)
提交回复
热议问题