2011-11-22 4 views
17

Tôi có một băm đơn giản và muốn trả về $ key dựa trên tiêu chí giá trị $. Tức là, đối với dòng 14, mã nào tôi sẽ cần trả về $ key trong đó giá trị $ là "vàng"?Tìm kiếm băm đơn giản theo giá trị

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

Trả lời

19

grep là công cụ thích hợp cho công việc này:

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

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

Không phải tất cả các giá trị đều là vô hướng. – codaddict

+3

'print" $ _ "foreach @ matching_keys' được viết tốt hơn là" print "@matching_keys" ', không có dấu cách như tiền thưởng. Ngoài ra, codaddict là chính xác, grep sẽ không hoạt động trên các giá trị là tham chiếu mảng. – TLP

2

Tôi không chắc chắn điều đó có hiệu quả với băm một chiều không. Toàn bộ điểm của một băm là chuyển đổi khóa thành một giá trị (hoặc vị trí của giá trị nếu bạn đang tìm kiếm dưới các trang bìa). Bạn có thể thực hiện tìm kiếm toàn diện trên tất cả các giá trị, thu thập các khóa khi bạn thực hiện nhưng điều đó không hiệu quả như tra cứu băm.

Để đi theo con đường khác một cách hiệu quả, bạn có thể muốn xem xét một băm hai chiều, một cái gì đó như:

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

Vì vậy, bạn có thể gọi nó là như vậy:

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

Tôi lưu ý ví dụ của bạn có tham chiếu đến các mảng vô danh, vì vậy tôi sẽ chỉ làm một foreach hơi dài/nếu vòng lặp:

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

Vì một số giá trị của bạn là mảng, bạn cần phải kiểm tra cho điều đó.

Calling:

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

Các chương trình con:

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

Sử dụng một regex thay vì eq là không bắt buộc, chỉ cần lưu tâm giữ cùng một vụ án, vì Yellowyellow là được coi là các khóa khác nhau.