2009-08-11 6 views
16

Aşağıdaki kod parçacığı, bir dizideki bir değerin ilk oluşumunun dizinini arar. Ancak, $ indeksi parantezleri kaldırıldığında, düzgün çalışmaz. Neyi yanlış yapıyorum?Perl grep'im neden ilk eşleşmeyi vermiyor?

my ($index) = grep { $array[$_] eq $search_for } 0..$#array; 

cevap

39

parantez grep içeriği listelemek için skalar bağlamdan değerlendirildiği içeriği değiştirmek. Skaler bağlamda grep ifadesinin gerçekleşme sayısını döndürür. Liste bağlamında, ifadenin doğru olduğu öğeleri döndürür.

aşağıdaki olayları fark bağlam yapar:

my $x = grep {/foo/} @array; # the number of things that match /foo/ 
my ($x) = grep {/foo/} @array; # the first thing that matches /foo/ 
my @foo = grep {/foo/} @array; # all the things that match /foo/ 
my (@foo) = grep {/foo/} @array; # all the things that match /foo/ 
+0

'scalar @ array',' dizi 'öğesinin sayısıdır –

1

grep bir listesini döndürür. Skaler değişken adını parantez içine koyduğunuzda, Perl tüm l değerini bir liste olarak kabul eder, bu nedenle listedeki ilk değeri bu değişkene atar.

parantez içinde diğer skalarlar olsaydı, onları grep 'ın dönüş diziden ikinci, üçüncü, vb değerleri almak istiyorum:

my ($index, $foo, $bar) = grep { $array[$_] eq $search_for } 0..$#array; 
+3

grep bir dizi döndürür. Ancak sadece dizi bağlamında. – innaM

+0

Ve skaler bağlamda, eşleşmenin gerçekte kaç kez döndüğünü döndürür, bu yüzden diziyi kimin skaler izlediği önemli değildir. – Plutor

+1

@Plutor: Dokümanlar açıkça grep'in ne yaptığını açık bir şekilde söylemiyor, dolayısıyla yanlış bir açıklama yayınlamak için bir gerekçe yok. –

8

parantezler grep için list context sağlarlar. grep, daha sonra ifadenin doğru olduğu ve yalnızca ifadenin doğru olduğu sayıda öğe listesi döndürecektir.

+0

s/dizi içeriği/liste içeriği/ –

+0

Daha iyi. Teşekkür ederim. – innaM

+0

Bir şey değil. –

7

Sana List::MoreUtils den first_index Aradığınız düşünüyorum:

use List::MoreUtils qw(first_index); 

# ... 

my $index = first_index { $_ eq $search_for } @array; 
5

grep fonksiyon listesi bağlam ve skaler bağlamında farklı davranır. Bu perldoc -f grep belgelenmiştir:

(her elemana $ _ ayar lokal ) LİSTESİ her bir öğesi için ENGELLEME veya expr değerlendirir ve ifade true değerlendirdi kendisi için bu elementten oluşan liste değerini döndürür. Skaler bağlamda, ifadesinin gerçekleşme sayısını döndürür.

Sen kötü adlı wantarray fonksiyonu ile kendi başınıza bu çoğaltabilirsiniz: hala yürümek zorunda çünkü sadece ilk örneği bulmak için, ben grep kullanarak düşünüyorum Ayrıca

sub my_grep { 
    my $sub = shift; 
    my @return; 
    for my $item (@_) { 
     push @return if $sub->($item); 
    } 
    return @return if wantarray; 
    return scalar @return; 
} 
1

biraz verimsiz ve dizinin her elemanında geri arama işlemini çalıştırın. Özellikle diziniz uzunsa, bir döngü yazarken veya yukarıda belirtildiği gibi List :: MoreUtils kullanarak daha iyi olabilirsiniz.