迭代Perl数组的最佳方法

时间:2012-05-07 18:43:13

标签: arrays perl iteration

哪个是迭代Perl数组的最佳实现(在速度和内存使用方面)?有没有更好的方法? (@Array无需保留)。

实施1

foreach (@Array)
{
      SubRoutine($_);
}

实施2

while($Element=shift(@Array))
{
      SubRoutine($Element);
}

实施3

while(scalar(@Array) !=0)
{
      $Element=shift(@Array);
      SubRoutine($Element);
}

实施4

for my $i (0 .. $#Array)
{
      SubRoutine($Array[$i]);
}

实施5

map { SubRoutine($_) } @Array ;

6 个答案:

答案 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还指出,除了速度之外,这些实施还有很多不同。