[arrays] Perl 배열을 반복하는 가장 좋은 방법

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) {
# ...
}

또는 perl5.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는 또한 속도 외에 이러한 구현에 상당한 차이가 있음을 지적합니다.


답변