2010-01-18 7 views
6

Son zamanlarda işlevsel programlama hakkında çok şey düşünüyordum. Perl bu şekilde ilerlemek için oldukça az araç sunuyor, ancak henüz bulamadığım bir şey var.Perl'de Prototip Enumerator.detect'in eşdeğerini en az kodla nasıl yapabilirim?

Prototip açıklamaları sadece bu, işlev sıralayıcısını için tespit var

yineleyici her eleman üzerinde sırayla uygulanan bir işlev için bir referans ise, bu durumda Sayım bir listesidir
Enumerator.detect(iterator[, context]) -> firstElement | undefined 
Finds the first element for which the iterator returns true. 

liste.

Performansın önemli olduğu durumlarda, örneğin bir eşleşme ile karşılaşıldığında durdurulduğunda, listenin geri kalanını göz ardı ederek zaman kazandırır.

Ayrıca, herhangi bir ekstra modül yüklemeyi içermeyen bir çözüm arıyorum, mümkünse sadece yerleşiklerle yapılmalıdır. Ve mümkünse örneğin bu kadar kısa olmalıdır:

my @result = map function @array; 
+7

"Langauge Y'den A'ya denk langauge X nedir?" Şeklindeki bir soruyu görmek güzel. A'nın yaptığı bir açıklama ile. Teşekkür ederim. – daotoad

cevap

15

Sen bir modül istemediklerini söyledi, ancak bu tam List::Util yılında first işlevi yaptığı iştir. Bu bir çekirdek modül, bu yüzden her yerde mevcut olmalı. Eğer bir modülü kullanarak değil ısrar ediyorsanız

use List::Util qw(first); 
my $first = first { some condition } @array; 

, sen Listesinde dışına uygulanmasını kopyalayabilirsiniz :: util. Birisi bunu yapmanın daha hızlı bir yolunu biliyorsa, orada olurdu. (Herhangi bir saf-Perl yaklaşımı daha muhtemelen daha hızlı yüzden, o Listesini :: Util bir XS uygulanmasını içerir unutmayın. Ayrıca Listesi'nde, :: Util :: PP first saf-Perl sürümü var.)

Not o Test edilen değer, parametre olarak $_ ve 'da alt programa aktarılır. Bu, first { some condition} @values formunu kullanırken kolaylık sağlar, ancak normal bir alt yordam kullanıyorsanız, hatırlamanız gereken bir şeydir. Biraz daha örnek:

use 5.010; # I want to use 'say'; nothing else here is 5.10 specific 
use List::Util qw(first); 

say first { $_ > 3 } 1 .. 10; # prints 4 

sub wanted { $_ > 4 }; # note we're using $_ not $_[0] 
say first \&wanted, 1 .. 10; # prints 5 

my $want = \&wanted;   # Get a subroutine reference 
say first \&$want, 1 .. 10; # This is how you pass a reference in a scalar 

# someFunc expects a parameter instead of looking at $_ 
say first { someFunc($_) } 1 .. 10; 
+4

+1 Liste :: Kullanım ve Liste :: MoreUtils çok işlevseldir - her şeyden önce, bir "azaltma" içerirler. :) – Ether

+0

Açıkladığınız için teşekkürler.Başka bir modüle girmemle ilgili ana kavrayışım, kazan plakasımın çok fazla artmasıydı, ama bu noktada Toolset'i kırmaktan kaçınamıyorum. Ayrıca, ikinci açıklamanızda, onları şu iki biçimde kullanıyor olacağım: benim $ res = first some_func, @array; Burada somefunc, $ _; ve: benim $ res = ilk some_func ($ _, 5), @array; Bazı_func, _'de bir alt harekettir. (En azından bunların harita için aynı şekilde çalışacağını umuyorum.) (Argh, yorumlarda formatlama yok. :() – Mithaldu

5

bu makinede Perl olmadığı için Untested, ancak: bu değil o

my $first = first { sub performing test } @list; 

Not:

sub first(\&@) { 
    my $pred = shift; 
    die "First argument to "first" must be a sub" unless ref $pred eq 'CODE'; 
    for my $val (@_) { 
     return $val if $pred->($val); 
    } 
    return undef; 
} 

Sonra olarak kullanmak Listedeki hiçbir eşleşmeyi ve listedeki öğelerin tanımlanmamış bir değer ile bu eşleşmeye sahip olmasını ayırt etmeyin. Sadece onun değil burada beri

+3

Bu, List :: Util :: PP'deki sürümle hemen hemen aynıdır. for döngüsünde sözcüksel bir değişken kullanmayın) – cjm

+0

Bilmekte fayda var, dediğim gibi, bu tamamen manşonun kapalı olduğunu söylemişti: – Dan

+2

Sözcüksel bir değişken kullanmamanın nedeni, alt testin test edilen değere işaret etmesini sağlamasıdır. '$ _' yerine $ _ [0]' (sürümünüzde yapmak zorunda olduğunuz gibi). – cjm

4

, onun blok için $_ lokalize ilk bir Perl işlevi tanımı:

sub first (&@) { 
    my $code = shift; 
    for (@_) {return $_ if $code->()} 
    undef 
} 

my @array = 1 .. 10; 
say first {$_ > 5} @array; # prints 6 

iyi çalışır iken List::Util bir çekirdek olduğu için ben bu sürümünü kullanarak savunan yok modül (varsayılan olarak yüklenmiş) ve first uygulaması, genellikle daha hızlı olan XS sürümünü (C ile yazılmış) kullanır.