Simple hash search by value

38,978

Solution 1

grep is the right tool for this job:

my @all_matches = grep { $fruit{$_} eq 'yellow' } keys %fruit;
print("$_ ") foreach @matching_keys;

my ($any_match) = grep { $fruit{$_} eq 'yellow' } keys %fruit;

Solution 2

I'm not so sure that's easy to do efficiently with a one-way hash. The whole point of a hash is to convert the key into a value (or position of the value if you're looking under the covers). You can do an exhaustive search over all the values, collecting the keys as you go but that's not as efficient as a hash lookup.

In order to go the other way efficiently, you might want to consider a two-way hash, something like:

%fruit = (
    'apple' => ['red','green'],
    'kiwi' => 'green',
    'banana' => 'yellow',
);
%antifruit = (
    'red' => 'apple',
    'green' => ['apple','kiwi'],
    'yellow' => 'banana',
);
print "The apple is @{$fruit{'apple'}}.\n";
print "The kiwi is $fruit{'kiwi'}.\n";
print "A yellow thing is $antifruit{'yellow'}.\n";

Solution 3

sub find_key { 
    my ( $h, $value ) = @_;
    while ( my ( $k, $v ) = each %$h ) { 
        return $k if $v eq $value;
    }
    return;
}

So you could call it like so:

find_key( \%fruit, 'yellow' );

Solution 4

Since some of your values are arrays, you need to check for that.

Calling:

my @fruit = getfruit(\%fruit, $colour);

The subroutine:

sub getfruit {
    my ($fruit, $col) = @_;
    my @result;
    for my $key (keys %$fruit) {
        if (ref $fruit->{$key} eq 'ARRAY') {
            for (@{$fruit->{$key}}) {
                push @result, $key if /^$col$/i;
            }
        } else {
            push @result, $key if $fruit->{$key} =~ /^$col$/i;
        }
    }
    return @result;
}

Using a regex instead of eq is optional, just be mindful of keeping the same case, since Yellow and yellow are considered different keys.

Share:
38,978
kurotsuki
Author by

kurotsuki

Hi :)

Updated on July 05, 2022

Comments

  • kurotsuki
    kurotsuki almost 2 years

    I have a simple hash, and would like to return the $key based on $value criteria. That is, for line 14, what code would I need to return the $key where the $value is "yellow"?

    1  #!/usr/bin/perl
    2
    3  # This program creates a hash then
    4  # prints out what is in the hash
    5
    6  %fruit = (
    7   'apple' => ['red','green'],
    8   'kiwi' => 'green',
    9   'banana' => 'yellow',
    10  );
    11
    12 print "The apple is @{$fruit{apple}}.\n";
    13 print "The kiwi is $fruit{kiwi}.\n";
    14 print "What is yellow? ";
    
  • TLP
    TLP over 12 years
    print "$_ " foreach @matching_keys better written as print "@matching_keys", with no trailing space as bonus. Also, codaddict is correct, grep will not work on the values that are array references.