Простой поиск по хешу по значению - PullRequest
19 голосов
/ 22 ноября 2011

У меня есть простой хэш, и я хотел бы вернуть ключ $ на основе критерия $ value.То есть, для строки 14, какой код мне нужно вернуть ключ $, где значение $ «желтый»?

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

Ответы [ 5 ]

21 голосов
/ 22 ноября 2011

grep правильный инструмент для этой работы:

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

my ($any_match) = grep { $fruit{$_} eq 'yellow' } keys %fruit;
2 голосов
/ 22 ноября 2011

Я не уверен, что это легко сделать эффективно с односторонним хешем. Весь смысл хэша состоит в том, чтобы преобразовать ключ в значение (или позицию значения, если вы смотрите под обложками). Вы можете выполнить исчерпывающий поиск по всем значениям, собирая ключи по ходу работы, но это не так эффективно, как поиск по хешу.

Чтобы эффективно пойти другим путем , вы можете рассмотреть двусторонний хэш, например:

%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";
1 голос
/ 22 ноября 2011

Поскольку некоторые из ваших значений являются массивами, вам необходимо проверить это.

Вызов:

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

Подпрограмма:

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;
}

Использование регулярных выражений вместо eq необязательно, просто помните о том, чтобы сохранить один и тот же регистр, поскольку Yellow и yellow считаются разными ключами.

1 голос
/ 22 ноября 2011
sub find_key { 
    my ( $h, $value ) = @_;
    while ( my ( $k, $v ) = each %$h ) { 
        return $k if $v eq $value;
    }
    return;
}

Чтобы вы могли назвать это так:

find_key( \%fruit, 'yellow' );
0 голосов
/ 22 ноября 2011

Замечу, что в вашем примере есть ссылки на анонимные массивы, поэтому я бы просто сделал длинный цикл foreach / if:

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";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...