2011-11-22 11 views
17

Ho un semplice hash e desidero restituire il tasto $ in base ai criteri $ value. Cioè, per la riga 14, di quale codice avrei bisogno per restituire la chiave $ in cui il valore $ è "giallo"?Ricerca hash semplice per valore

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

risposta

19

grep è lo strumento giusto per questo lavoro:

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

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

Non tutti i valori sono scalari. – codaddict

+3

'stampa" $ _ "foreach @ matching_keys' meglio scritto come' print "@matching_keys" ', senza spazio finale come bonus. Inoltre, codaddict è corretto, grep non funzionerà sui valori che sono riferimenti di array. – TLP

2

Non sono così sicuro che sia facile da fare in modo efficiente con un hash unidirezionale. L'intero punto di un hash è convertire la chiave in un valore (o posizione del valore se stai guardando sotto le copertine). È possibile eseguire una ricerca esaustiva su tutti i valori, raccogliendo le chiavi mentre si va, ma non è efficiente come una ricerca hash.

Al fine di andare nella direzione opposta in modo efficiente, si potrebbe prendere in considerazione un hash a due vie, qualcosa di simile:

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

così si potrebbe chiamare in questo modo:

find_key(\%fruit, 'yellow'); 
0

io notare il vostro esempio ha riferimenti ad array anonimi, quindi vorrei solo fare una lunga foreach fiato/se ciclo:

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

Dal momento che alcuni dei vostri valori sono gli array, è necessario controllare per questo.

Calling:

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

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

Usando un'espressione regolare invece di eq è facoltativo, solo essere consapevoli di mantenere lo stesso caso, dal momento che Yellow e yellow sono considerato chiavi diverse

Problemi correlati