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 ;
답변
-
속도 측면에서 : # 1 및 # 4이지만 대부분의 경우 그다지 많지는 않습니다.
확인을 위해 벤치 마크를 작성할 수 있지만 반복 작업이 Perl 대신 C에서 수행되고 배열 요소의 불필요한 복사가 발생하지 않기 때문에 # 1과 # 4가 약간 더 빠르다고 생각합니다. ( # 1의 요소에 별칭
$_
이 지정 되지만 # 2 및 # 3은 실제로 배열에서 스칼라를 복사 합니다.)# 5는 비슷할 수 있습니다.
-
메모리 사용량 측면에서 : # 5를 제외하고 모두 동일합니다.
for (@a)
어레이를 평평하게하지 않도록 특수한 경우입니다. 루프는 배열의 인덱스를 반복합니다. -
가독성 측면에서 : # 1.
-
유연성 측면에서 : # 1 / # 4 및 # 5.
# 2는 거짓 요소를 지원하지 않습니다. # 2와 # 3은 파괴적입니다.
답변
의 요소에만 관심이 있다면 다음을 @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
.
이러한 패턴이 아닌 다른 패턴은 특정 상황에서 적절할 수 있습니다.
답변
IMO, 구현 # 1은 일반적이며 Perl의 경우 짧고 관용적 인 것이 다른 것보다 우선합니다. 세 가지 선택에 대한 벤치 마크는 최소한 속도에 대한 통찰력을 제공 할 수 있습니다.
답변
1은 배열을 그대로두고 나머지 두 개는 비워두기 때문에 2 및 3과 실질적으로 다릅니다.
# 3은 꽤 엉뚱하고 아마도 덜 효율적이라고 말하고 싶습니다.
그러면 # 1과 # 2가 남습니다. 그들은 같은 일을하지 않습니다. 그래서 하나가 다른 것보다 “더 나을”수 없습니다. 배열이 크고 보관할 필요가없는 경우 일반적으로 범위가 처리하므로 ( 참고 참조 ) 일반적으로 # 1이 여전히 가장 명확하고 간단한 방법입니다. 각 요소를 해제해도 속도가 빨라지지는 않습니다. 참조에서 배열을 해제해야하는 경우에도 그냥 가겠습니다.
undef @Array;
완료되면.
- 참고 : 배열의 범위를 포함하는 서브 루틴은 실제로 배열을 유지하고 다음에 공간을 재사용합니다. 일반적으로 괜찮습니다 (댓글 참조).
답변
한 줄로 요소 또는 배열을 인쇄합니다.
(@array에 대해 $ _ 인쇄);
참고 : $ _는 내부적으로 @array in loop의 요소를 참조합니다. $ _에서 변경 한 사항은 @array에 반영됩니다.
전의.
my @array = qw( 1 2 3 );
for (@array) {
$_ = $_ *2 ;
}
print "@array";
출력 : 24 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,
});
x86_64-linux-gnu-thread-multi 용으로 빌드 된 perl 5, 버전 24, 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)
따라서 ‘foreach (@Array)’는 다른 것보다 약 2 배 빠릅니다. 다른 모든 것은 매우 유사합니다.
@ikegami는 또한 속도 외에 이러한 구현에 상당한 차이가 있음을 지적합니다.