Perl Goatse的“秘密操作员"有效吗? [英] Is the Perl Goatse 'Secret Operator' efficient?

查看:119
本文介绍了Perl Goatse的“秘密操作员"有效吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Perl中的山羊运算符"或=()=惯用语使表达式在列表上下文中求值.

The "goatse operator" or the =()= idiom in Perl causes an expression to be evaluated in list context.

一个例子是:

my $str = "5 and 4 and a 3 and 2 1 BLAST OFF!!!";
my $count =()= $str =~ /\d/g; # 5 matches...
print "There are $count numbers in your countdown...\n\n";

在我解释用法时,会发生以下情况:

As I interprete the use, this is what happens:

  1. $str =~ /\d/g匹配所有数字. g开关和列表上下文会生成这些匹配项的列表.让它成为列表生产者"示例,在Perl中可能有很多事情.
  2. =()=导致分配给一个空列表,因此所有实际匹配项都将被复制到一个空列表中.
  3. 在标量上下文中对2中生成的列表的$ count的赋值给出列表的计数或结果5.
  4. 在分配标量后,空列表=()=的引用计数变为零.然后,Perl删除列表元素的副本.
  1. $str =~ /\d/g matches all the digits. The g switch and list context produces a list of those matches. Let this be the "List Producer" example, and in Perl this could be many things.
  2. the =()= causes an assignment to an empty list, so all the actual matches are copied to an empty list.
  3. The assignment in scalar context to $count of the list produced in 2. gives the count of the list or the result of 5.
  4. The reference count of the empty list =()= goes to zero after the scalar assignment. The copy of the list elements is then deleted by Perl.

关于效率的问题是这些:

The questions on efficiency are these:

  1. 我在解析此内容时错了吗?
  2. 如果您有一些列表生产者,并且您只对计数感兴趣,是否有更有效的方法来做到这一点?

此微不足道的列表非常有用,但是如果列表中有成千上万的匹配项怎么办?使用这种方法,您将生成每个匹配项的完整副本,然后将其删除只是为了对它们进行计数.

It works great with this trivial list, but what if the list was hundreds of thousands of matches? With this method you are producing a full copy of every match then deleting it just to count them.

推荐答案

Perl 5在复制列表方面很聪明.它仅复制左侧的项目.之所以有效,是因为标量上下文中的列表分配会产生右侧的项数.因此,n项将由正则表达式创建,但不会被复制和丢弃,而只会被丢弃.您可以在下面的基准测试中看到额外副本在幼稚的情况下所产生的差异.

Perl 5 is smart about copying lists. It only copies as many items as are on the left hand side. It works because list assignment in scalar context yields the number of items on the right hand side. So, n items will be created by the regex, but they won't be copied and discarded, just discarded. You can see the difference the extra copy makes in the naive case in the benchmark below.

关于效率,迭代解决方案通常在内存和CPU使用上更容易,但是必须权衡山羊胡子秘密运算符的简洁性.以下是对各种解决方案进行基准测试的结果:

As for efficiency, an iterative solution is often easier on memory and CPU usage, but this must be weighed against the succinctness of the goatse secret operator. Here are the results of benchmarking the various solutions:

naive: 10
iterative: 10
goatse: 10

for 0 items:
               Rate iterative    goatse     naive
iterative 4365983/s        --       -7%      -12%
goatse    4711803/s        8%        --       -5%
naive     4962920/s       14%        5%        --

for 1 items:
               Rate     naive    goatse iterative
naive      749594/s        --      -32%      -69%
goatse    1103081/s       47%        --      -55%
iterative 2457599/s      228%      123%        --

for 10 items:
              Rate     naive    goatse iterative
naive      85418/s        --      -33%      -82%
goatse    127999/s       50%        --      -74%
iterative 486652/s      470%      280%        --

for 100 items:
             Rate     naive    goatse iterative
naive      9309/s        --      -31%      -83%
goatse    13524/s       45%        --      -76%
iterative 55854/s      500%      313%        --

for 1000 items:
            Rate     naive    goatse iterative
naive     1018/s        --      -31%      -82%
goatse    1478/s       45%        --      -75%
iterative 5802/s      470%      293%        --

for 10000 items:
           Rate     naive    goatse iterative
naive     101/s        --      -31%      -82%
goatse    146/s       45%        --      -75%
iterative 575/s      470%      293%        --

这是生成它的代码:

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark;

my $s = "a" x 10;

my %subs = (
    naive => sub {
        my @matches = $s =~ /a/g;
        return scalar @matches;
    },
    goatse => sub {
        my $count =()= $s =~ /a/g;
        return $count;
    },
    iterative => sub {
        my $count = 0;
        $count++ while $s =~ /a/g;
        return $count;
    },
);

for my $sub (keys %subs) {
    print "$sub: @{[$subs{$sub}()]}\n";
}

for my $n (0, 1, 10, 100, 1_000, 10_000) {
    $s = "a" x $n;
    print "\nfor $n items:\n";
    Benchmark::cmpthese -1, \%subs;
}

这篇关于Perl Goatse的“秘密操作员"有效吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆