我如何用最少量的代码在Perl中使用Prototype的Enumerator.detect?

Mit*_*ldu 6 perl functional-programming

最近我一直在思考函数式编程.Perl提供了相当多的工具,但是有些东西我还没有找到.

Prototype具有枚举器的函数检测功能,描述就是这样:

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

在这种情况下,枚举器是任何列表,而迭代器是对函数的引用,该函数依次应用于列表的每个元素.

我期待这样的事情在的情况下申请在性能是重要的,即在遇到比赛停止时无视列表的其余部分节省了时间.

我也在寻找一种不涉及加载任何额外模块的解决方案,所以如果可能的话,应该只使用内置模块.如果可能的话,它应该像这样简洁:

my @result = map function @array;
Run Code Online (Sandbox Code Playgroud)

cjm*_*cjm 15

你说你不想要一个模块,但是这也正是first在功能列表::的Util一样.这是一个核心模块,所以应该随处可用.

use List::Util qw(first);
my $first = first { some condition } @array;
Run Code Online (Sandbox Code Playgroud)

如果您坚持不使用模块,则可以将实现复制出List :: Util.如果有人知道更快的方法,它会在那里.(请注意,List :: Util包含一个XS实现,因此可能比任何纯Perl方法更快.它first在List :: Util :: PP中也有一个纯Perl版本.)

请注意,正在测试的值将传递给子例程,$_不是作为参数传递.当您使用first { some condition} @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; 
Run Code Online (Sandbox Code Playgroud)

  • +1 List :: Util和List :: MoreUtils非常实用 - 毕竟,它们甚至包含一个`reduce`.:) (4认同)

Dan*_*Dan 5

未经测试,因为我在这台机器上没有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;
}
Run Code Online (Sandbox Code Playgroud)

然后用它作为:

my $first = first { sub performing test } @list;
Run Code Online (Sandbox Code Playgroud)

请注意,这并不区分列表中没有匹配项,列表中的一个元素是未定义的值并且具有该匹配项.

  • 这与List :: Util :: PP中的版本几乎相同(除了在for循环中不使用词法变量). (3认同)
  • 不使用词法变量的原因是它允许sub将被测试的值称为`$ _`而不是`$ _ [0]`(正如你在你的版本中所做的那样). (2认同)