web-dev-qa-db-fra.com

Recherche simple par hachage par valeur

J'ai un hachage simple et je voudrais renvoyer la clé $ basée sur les critères de valeur $. C'est-à-dire que pour la ligne 14, de quel code aurais-je besoin pour renvoyer la clé $ où la valeur de $ est "jaune"?

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

grep est le bon outil pour ce travail:

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

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

Je ne suis pas sûr que ce soit facile à faire efficacement avec un hash à sens unique. L'intérêt d'un hachage est de convertir la clé en une valeur (ou la position de la valeur si vous regardez sous les couvertures). Vous pouvez effectuer une recherche exhaustive sur toutes les valeurs, en collectant les clés au fur et à mesure, mais ce n'est pas aussi efficace qu'une recherche de hachage.

Pour aller dans le sens contraire efficacement,, vous pouvez envisager un hachage bidirectionnel, quelque chose comme:

%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";
2
paxdiablo
sub find_key { 
    my ( $h, $value ) = @_;
    while ( my ( $k, $v ) = each %$h ) { 
        return $k if $v eq $value;
    }
    return;
}

Pour que vous puissiez l'appeler ainsi: 

find_key( \%fruit, 'yellow' );
1
Axeman

Certaines de vos valeurs étant des tableaux, vous devez vérifier cela.

Appeler:

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

Le sous-programme:

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

Utiliser une expression rationnelle à la place de eq est optionnel, gardez toujours le même cas, car Yellow et yellow sont considérés comme des clés différentes.

1
TLP

Je remarque que votre exemple contient des références à des tableaux anonymes. Je ferais donc une longue boucle 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";
0
Drav Sloan