代码之家  ›  专栏  ›  技术社区  ›  Mithaldu

我该如何用最少的代码在Perl中实现与原型枚举器的等效。

  •  6
  • Mithaldu  · 技术社区  · 15 年前

    最近我一直在思考函数式编程。Perl提供了很多这样的工具,但是我还没有找到。

    Prototype具有枚举器检测功能,其描述如下:

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

    在本例中,枚举器是任何列表,而迭代器是对函数的引用,该函数依次应用于列表的每个元素。

    我正在寻找这样的东西,以适用于性能很重要的情况,即,当遇到一场比赛停止时,通过忽略列表的其余部分节省时间。

    我也在寻找一个不涉及加载任何额外模块的解决方案,因此如果可能的话,应该只使用内置模块。如果可能的话,它应该像下面这样简洁,例如:

    my @result = map function @array;
    
    3 回复  |  直到 15 年前
        1
  •  15
  •   cjm    15 年前

    你说你不想要模块,但这正是 first 功能在 List::Util 做。这是一个核心模块,所以应该可以在任何地方使用。

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

    如果您坚持不使用模块,则可以将实现从list::util中复制出来。如果有人知道一个更快的方法,它会在那里。(请注意,list::util包含一个XS实现,因此这可能比任何纯Perl方法都要快。它还具有纯Perl版本的 第一 ,在列表中::util::pp.)

    请注意,正在测试的值在 $_ 作为参数。当您使用 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; 
    
        2
  •  5
  •   Dan    15 年前

    因为我在这台机器上没有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;
    

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

        3
  •  4
  •   Eric Strom    15 年前

    因为它不在这里,所以第一个本地化的Perl函数定义 $_ 对于其块:

    sub first (&@) {
        my $code = shift;
        for (@_) {return $_ if $code->()}
        undef
    }
    
    my @array = 1 .. 10;
    say first {$_ > 5} @array; # prints 6
    

    虽然它可以很好地工作,但我不提倡使用这个版本,因为 List::Util 是核心模块(默认情况下安装),其实现 first 通常会使用XS版本(用C编写),这要快得多。

    推荐文章