哪个是迭代Perl数组的最佳实现(在速度和内存使用方面)?有没有更好的方法? (@Array
无需保留)。
foreach (@Array)
{
SubRoutine($_);
}
while($Element=shift(@Array))
{
SubRoutine($Element);
}
while(scalar(@Array) !=0)
{
$Element=shift(@Array);
SubRoutine($Element);
}
for my $i (0 .. $#Array)
{
SubRoutine($Array[$i]);
}
map { SubRoutine($_) } @Array ;
答案 0 :(得分:72)
就速度而言:#1和#4,但在大多数情况下并不多。
您可以编写一个基准来确认,但我怀疑您会发现#1和#4稍快一些,因为迭代工作是在C而不是Perl中完成的,并且不会发生任何不必要的数组元素复制。 ($_
别名到#1中的元素,但#2和#3实际上复制数组中的标量。)
#5可能类似。
就内存使用而言:除了#5之外,它们都是一样的。
for (@a)
是特殊的,以避免扁平化阵列。循环遍历数组的索引。
在可读性方面:#1。
在灵活性方面:#1 /#4和#5。
#2不支持false的元素。 #2和#3具有破坏性。
答案 1 :(得分:23)
如果您只关心@Array
的元素,请使用:
for my $el (@Array) {
# ...
}
或
如果指数很重要,请使用:
for my $i (0 .. $#Array) {
# ...
}
或者,从perl
5.12.1开始,您可以使用:
while (my ($i, $el) = each @Array) {
# ...
}
如果你需要循环体中的元素及其索引,我希望使用each
是最快的,但是你将放弃与5.12.1之前perl
的兼容性。
在某些情况下,某些其他模式可能是合适的。
答案 2 :(得分:3)
IMO,实施#1是典型的,并且简短而且惯用于Perl仅仅因为它而胜过其他人。三种选择的基准可能会让您深入了解速度。
答案 3 :(得分:2)
1与2和3大不相同,因为它使阵列保持完整,而其他两个则留空。
我会说#3非常古怪,可能效率不高,所以不要忘了。
这会让你失去#1和#2,他们不会做同样的事情,所以一个人不能比另一个人“更好”。如果数组很大并且您不需要保留它,通常范围将处理它(但参见 注意),所以<通常,#1仍然是最清晰,最简单的方法。关闭每个元素不会加速任何事情。即使需要从引用中释放数组,我也会去:
undef @Array;
完成后。
答案 4 :(得分:0)
以单行打印元素或数组。
打印$ _ for(@array);
注意:请记住$ _在内部引用循环中@array的元素。 $ _中所做的任何更改都将反映在@array; 中 恩。
my @array = qw( 1 2 3 );
for (@array) {
$_ = $_ *2 ;
}
print "@array";
输出:2 4 6
答案 5 :(得分:0)
决定这样的问题的最佳方法是对它们进行基准测试:
use strict;
use warnings;
use Benchmark qw(:all);
our @input_array = (0..1000);
my $a = sub {
my @array = @{[ @input_array ]};
my $index = 0;
foreach my $element (@array) {
die unless $index == $element;
$index++;
}
};
my $b = sub {
my @array = @{[ @input_array ]};
my $index = 0;
while (defined(my $element = shift @array)) {
die unless $index == $element;
$index++;
}
};
my $c = sub {
my @array = @{[ @input_array ]};
my $index = 0;
while (scalar(@array) !=0) {
my $element = shift(@array);
die unless $index == $element;
$index++;
}
};
my $d = sub {
my @array = @{[ @input_array ]};
foreach my $index (0.. $#array) {
my $element = $array[$index];
die unless $index == $element;
}
};
my $e = sub {
my @array = @{[ @input_array ]};
for (my $index = 0; $index < $#array; $index++) {
my $element = $array[$index];
die unless $index == $element;
}
};
my $f = sub {
my @array = @{[ @input_array ]};
while (my ($index, $element) = each @array) {
die unless $index == $element;
}
};
my $count;
timethese($count, {
'1' => $a,
'2' => $b,
'3' => $c,
'4' => $d,
'5' => $e,
'6' => $f,
});
在perl 5,版本24,为x86_64-linux-gnu-thread-multi
构建的subversion 1(v5.24.1)上运行我明白了:
Benchmark: running 1, 2, 3, 4, 5, 6 for at least 3 CPU seconds...
1: 3 wallclock secs ( 3.16 usr + 0.00 sys = 3.16 CPU) @ 12560.13/s (n=39690)
2: 3 wallclock secs ( 3.18 usr + 0.00 sys = 3.18 CPU) @ 7828.30/s (n=24894)
3: 3 wallclock secs ( 3.23 usr + 0.00 sys = 3.23 CPU) @ 6763.47/s (n=21846)
4: 4 wallclock secs ( 3.15 usr + 0.00 sys = 3.15 CPU) @ 9596.83/s (n=30230)
5: 4 wallclock secs ( 3.20 usr + 0.00 sys = 3.20 CPU) @ 6826.88/s (n=21846)
6: 3 wallclock secs ( 3.12 usr + 0.00 sys = 3.12 CPU) @ 5653.53/s (n=17639)
所以&#39; foreach(@Array)&#39;大约是其他人的两倍。所有其他人都很相似。
@ikegami还指出,除了速度之外,这些实施还有很多不同。