结合了 `foreach` 和 `if` 的 Perl 语法:它不应该起作用,即:为什么它不起作用?
Perl Syntax combining `foreach` and `if`: Shouldn't it work, i.e.: Why doesn't it work?
尝试获取不能包含负数的数组中的最大值我试过:
my @v;
#...
my $max = 0;
$max = $_
if ($_ > $max)
foreach (@v);
我收到 perl 5.18.2 的语法错误。
但是(1)statement($_) foreach (@v);
和(2)$max = $_ if ($_ > $max);
都还可以,他们做了他们应该做的。
那么如果 (1) 和 (2) 都是有效的陈述,为什么不能将它们组合在用于 (1) 的模式中?
只是没有人需要建议;这是我使用不同语法解决问题的方法:
foreach (@v) {
$max = $_
if ($_ > $max);
}
So if (1) and (2) are both valid statements, why can't they be combined in the pattern used for (1)?
您在这里使用的后缀语法(又名语句修饰符)不支持这种语句。
documentation says(强调我的):
Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending).
至于您的任务本身:从数组中获取最大值是一个非常常见的要求。一种简单且标准的方法使用 function max()
from core module List::Util
:
use List::Util qw/max/;
my @v;
my $max = max 0, @v;
我将添加这个更通用的答案,因为想要组合 for
和 if
语句修饰符是很常见的,不仅适用于可以使用(更快的)CPAN 模块的微不足道的情况.
您可能不想执行使用块的标准 foreach 的原因是,块会花费时间,如果循环内部发生的事情很慢,这可能无关紧要,但如果您正在做某事,则可能会超过 10% 的开销就像一个简单的任务。例如这个简单的例子:
my @v = map { rand } ( 1..100 );
cmpthese(-2, {
postfix => sub {
my $last;
$last = $_ for @v;
},
block => sub {
my $last;
foreach (@v) {$last = $_}
},
});
给我:
Rate block postfix
block 214369/s -- -11%
postfix 241751/s 13% --
所以...虽然您不能使用两个语句修饰符(后缀 if
、for
),但大多数时候您可以将 for
替换为 map
,保持无块循环的速度。例如 OP 的例子是 map {$max = $_ if $_ > $max} @v
和基准测试:
my @v = map { rand } ( 1..100 );
cmpthese(-2, {
map => sub {
my $max = 0;
map {$max = $_ if $_ > $max} @v;
},
foreach => sub {
my $max = 0;
foreach (@v) {$max = $_ if $_ > $max}
},
});
给出:
Rate foreach map
foreach 205585/s -- -13%
map 236303/s 15% --
正如我所说,在特定情况下,您绝对应该使用用 C 编写的 List::Util
,速度会快一个数量级...
尝试获取不能包含负数的数组中的最大值我试过:
my @v;
#...
my $max = 0;
$max = $_
if ($_ > $max)
foreach (@v);
我收到 perl 5.18.2 的语法错误。
但是(1)statement($_) foreach (@v);
和(2)$max = $_ if ($_ > $max);
都还可以,他们做了他们应该做的。
那么如果 (1) 和 (2) 都是有效的陈述,为什么不能将它们组合在用于 (1) 的模式中?
只是没有人需要建议;这是我使用不同语法解决问题的方法:
foreach (@v) {
$max = $_
if ($_ > $max);
}
So if (1) and (2) are both valid statements, why can't they be combined in the pattern used for (1)?
您在这里使用的后缀语法(又名语句修饰符)不支持这种语句。
documentation says(强调我的):
Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending).
至于您的任务本身:从数组中获取最大值是一个非常常见的要求。一种简单且标准的方法使用 function max()
from core module List::Util
:
use List::Util qw/max/;
my @v;
my $max = max 0, @v;
我将添加这个更通用的答案,因为想要组合 for
和 if
语句修饰符是很常见的,不仅适用于可以使用(更快的)CPAN 模块的微不足道的情况.
您可能不想执行使用块的标准 foreach 的原因是,块会花费时间,如果循环内部发生的事情很慢,这可能无关紧要,但如果您正在做某事,则可能会超过 10% 的开销就像一个简单的任务。例如这个简单的例子:
my @v = map { rand } ( 1..100 );
cmpthese(-2, {
postfix => sub {
my $last;
$last = $_ for @v;
},
block => sub {
my $last;
foreach (@v) {$last = $_}
},
});
给我:
Rate block postfix block 214369/s -- -11% postfix 241751/s 13% --
所以...虽然您不能使用两个语句修饰符(后缀 if
、for
),但大多数时候您可以将 for
替换为 map
,保持无块循环的速度。例如 OP 的例子是 map {$max = $_ if $_ > $max} @v
和基准测试:
my @v = map { rand } ( 1..100 );
cmpthese(-2, {
map => sub {
my $max = 0;
map {$max = $_ if $_ > $max} @v;
},
foreach => sub {
my $max = 0;
foreach (@v) {$max = $_ if $_ > $max}
},
});
给出:
Rate foreach map foreach 205585/s -- -13% map 236303/s 15% --
正如我所说,在特定情况下,您绝对应该使用用 C 编写的 List::Util
,速度会快一个数量级...