Simple hash search by value

风格不统一 提交于 2019-12-19 05:06:55

问题


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? ";

回答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;



回答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";



回答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' );



回答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.




回答5:


I note your example has references to anonymous arrays, so I would just do a long winded foreach/if loop:

my %fruit = (
  'apple' => ['red','green'],
  'kiwi' => 'green',
  'banana' => 'yellow',
);

print "The apple is @{$fruit{apple}}.\n";
print "The kiwi is $fruit{kiwi}.\n";
print "What is yellow? ";

my $ele;
my $search = 'yellow';
my @match = ();

foreach $ele (keys(%fruit)) {
    if(ref($fruit{$ele}) eq 'ARRAY' and
        grep { $_ eq $search } @{ $fruit{$ele} }) {
        push(@match, $ele);
    } elsif(!ref($fruit{$ele}) and $fruit{$ele} eq $search) {
        push(@match, $ele);
    }
}
print join(", ", @match) . "\n";


来源:https://stackoverflow.com/questions/8221463/simple-hash-search-by-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!