Arrays 遍历Perl数组的最佳方法
在速度和内存使用方面,迭代Perl数组的最佳实现是什么?还有更好的办法吗?(Arrays 遍历Perl数组的最佳方法,arrays,perl,iteration,Arrays,Perl,Iteration,在速度和内存使用方面,迭代Perl数组的最佳实现是什么?还有更好的办法吗?(@Array无需保留) 实施1 实施2 执行情况3 执行情况4 执行情况5 1与2和3有本质上的不同,因为它使数组保持不变,而其他两个使数组保持为空 我得说#3相当古怪,效率可能更低,所以别提了 这就给你留下了#1和#2,它们做的事情不一样,所以一个不能比另一个“更好”。如果数组很大,您不需要保留它,则scope通常会处理它(但请参见注意),因此一般来说,#1仍然是最清晰、最简单的方法。关闭每个元件不会加快任何速度。即使
@Array
无需保留)
实施1
实施2
执行情况3
执行情况4
执行情况5
1与2和3有本质上的不同,因为它使数组保持不变,而其他两个使数组保持为空 我得说#3相当古怪,效率可能更低,所以别提了 这就给你留下了#1和#2,它们做的事情不一样,所以一个不能比另一个“更好”。如果数组很大,您不需要保留它,则scope通常会处理它(但请参见注意),因此一般来说,#1仍然是最清晰、最简单的方法。关闭每个元件不会加快任何速度。即使需要将数组从引用中释放出来,我也会:
undef @Array;
完成后
- 注意:包含数组范围的子例程实际上保留了数组,并在下次重新使用该空间。一般来说,这应该没问题(见评论)
- 就速度而言:#1和#4,但在大多数情况下并不多
您可以编写一个基准来确认,但我怀疑您会发现#1和#4稍微快一点,因为迭代工作是用C而不是Perl完成的,并且不会发生不必要的数组元素复制。(
别名为#1中的元素,但#2和#3实际上从数组中复制了标量。) #5可能是相似的$
- 在内存使用方面:除了#5之外,它们都是相同的
(@a)的
是特殊情况,以避免阵列扁平化。循环遍历数组的索引
- 在可读性方面:#1
- 在灵活性方面:1/4和5 #2不支持为false的元素#2和#3具有破坏性
@Array
的元素,请使用:
for my $el (@Array) {
# ...
}
或
如果指数重要,请使用:
for my $i (0 .. $#Array) {
# ...
}
或者,从perl
5.12.1开始,您可以使用:
while (my ($i, $el) = each @Array) {
# ...
}
如果您需要在循环体中同时使用元素及其索引,我希望使用每个
都是最快的,但是您将放弃与5.12.1之前的perl
s的兼容性
在某些情况下,除此之外的其他一些图案可能是合适的。在单行中打印元素或数组 打印(@array)的$uu 注意:请记住,$\在内部是指循环中@array的元素。美元的任何更改都将反映在@array中强> 前
输出:2 4 6决定此类问题的最佳方法是对其进行基准测试:
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,
});
因此,“foreach(@Array)”的速度大约是其他的两倍。其他的都很相似
@ikegami还指出,除了速度之外,这些实现还有很多不同之处。为什么会有“最佳”呢?特别是考虑到我们不知道你会如何衡量彼此(速度比内存使用更重要吗?
map
和可接受的答案?等等),你发布的三个选项中的两个会让我去“WTH?!”,除非有额外的周围环境使它们成为明智的选择。在任何情况下,这个问题都处于“添加两个数字的最佳方式是什么?”的水平,大多数情况下,只有一种方式。然后,在这些情况下,你需要一种不同的方式。投票结束。@SinanÜnür我同意你的观点(只有一种方法可以将两个数字相加),但这个类比不够有力,不能轻蔑地使用。显然,有不止一种方法,OP希望了解什么是好主意,什么不是。Perl编程第三版第24章有一节是关于效率的,这是一本很好的书。它解决了不同类型的效率,如时间、程序员、维护人员。本节以“请注意,时间优化有时可能会降低您的空间或程序员效率(由下面冲突的提示指示)。这就是中断”这句话开始。添加两个数字的一种方法?如果您查看较低级别的调用/实现,则不会。。。。考虑进位先行、进位保存加法器等。@Array=()代码>不会释放基础数组。即使超出范围也不会这样做。如果你想释放底层数组,你必须使用undf@array代码>演示<代码>perl-MDevel::Peek-e'my@a;转储(\@a,1)@a=qw(a b c);转储(\@a,1)@a=();转储(\@a,1);未定义@a;转储(\@a,1);'2> &1| grep数组
什么???我原以为GC的全部要点是一旦ref count==0,所涉及的内存就可以回收。@ikegami:我看到了()
vsundef
,但是如果超出作用域并没有释放该作用域本地数组使用的内存,这难道不会使perl成为泄漏灾难吗?那不可能是真的。它们也不会泄漏。sub仍然拥有它们,并将在下次调用sub时重用它们。优化了速度。我希望每一个都是最慢的。它完成了其他人的所有工作,减去一个别名,再加上一个列表分配,两个标量副本和两个标量清除。使用对数组的索引进行迭代时大约快45%,对数组引用的索引进行迭代时快20%(我确实访问了$array->[$I]
,在正文中),使用每个与同时使用.Wow,你用简短的句子添加了大量的信息。#2在排队时很有用(例如广度优先搜索):my@todo=$root;而(@todo){my$node=shift。。。;
undef @Array;
for my $el (@Array) {
# ...
}
for my $i (0 .. $#Array) {
# ...
}
while (my ($i, $el) = each @Array) {
# ...
}
my @array = qw( 1 2 3 );
for (@array) {
$_ = $_ *2 ;
}
print "@array";
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,
});
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)