Как я сделал бы эквивалент Enumerator.detect Прототипа в Perl с наименьшим количеством объема кода?

В последнее время я думал много о функциональном программировании. Perl предлагает довольно много инструментов, чтобы пойти тем путем, однако существует что-то, что я не смог найти все же.

Прототип имеет функцию, обнаруживают для перечислителей, описания просто это:

Enumerator.detect(iterator[, context]) -> firstElement | undefined
Finds the first element for which the iterator returns true.

Перечислитель в этом случае является любым списком, в то время как итератор является ссылкой на функцию, которая применяется в свою очередь на каждом элементе списка.

Я ищу что-то вроде этого для применения в ситуациях, где производительность важна, т.е. когда остановка после обнаружения с соответствием экономит время путем игнорирования остальной части списка.

Я также ищу решение, которое не включило бы загрузку никакого дополнительного модуля, поэтому если возможный это должно быть сделано с builtins только. И, если возможно, это должно быть столь же кратко как это, например:

my @result = map function @array;
6
задан Mithaldu 18 January 2010 в 22:40
поделиться

3 ответа

Вы говорите, что не хотите модуль, но это именно то, что функция first в List::Util does::Util. Это основной модуль, поэтому он должен быть доступен везде.

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

Если вы настаиваете на том, чтобы не использовать модуль, вы можете скопировать реализацию из List::Util. Если бы кто-то знал более быстрый способ сделать это, он был бы там. (Обратите внимание, что List::Util включает в себя реализацию XS, так что это, вероятно, быстрее, чем любой подход на чистом Perl. Она также имеет чистую перловую версию first, в List::Util::PP.)

Обратите внимание, что тестируемое значение передается в подпрограмму в $_ и а не в качестве параметра. Это удобно, когда вы сначала используете {некоторый параметр}. @values форма, но это то, что вы должны помнить, если вы используете обычную подпрограмму. Еще несколько примеров:

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; 
15
ответ дан 8 December 2019 в 04:52
поделиться

непроверенный, так как у меня нет Perl на этой машине, но:

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

затем используйте его как:

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

Обратите внимание, что это не различает совпадающих в списке, а один из элементов в списке неопределенное значение и имеющее этот матч.

5
ответ дан 8 December 2019 в 04:52
поделиться

Также с тех пор не здесь, определение функции Perl первого, которое локализует $ _ для его блока:

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

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

, пока оно будет работать нормально, я не защищаю эту версию, так как Список :: util - это основной модуль (установленный по умолчанию), а его реализация сначала обычно использует версию XS (написанную в C), которая намного быстрее.

4
ответ дан 8 December 2019 в 04:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: