Najlepszy sposób na iterację poprzez tablicę Perla

Jaka jest najlepsza implementacja (pod względem szybkości i wykorzystania pamięci) do iteracji poprzez tablicę Perla? Jest jakiś lepszy sposób? ({[5] } nie muszą być zachowane).

Implementacja 1

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

Implementacja 2

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

Implementacja 3

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

Implementacja 4

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

Implementacja 5

map { SubRoutine($_) } @Array ;
Author: Jean, 2012-05-07

6 answers

  • Pod względem szybkości :# 1 i # 4, ale w większości przypadków niewiele.

    Możesz napisać benchmark, aby potwierdzić, ale podejrzewam, że #1 i #4 będą nieco szybsze, ponieważ iteracja jest wykonywana w C zamiast w Perlu i nie ma potrzeby kopiowania elementów tablicy. ($_ jest aliasowane do elementu w #1, ale #2 i #3 faktycznie kopiują Skalary z tablicy.)

    #5 może być podobne.

  • W kategoriach wykorzystanie pamięci: Wszystkie są takie same, z wyjątkiem # 5.

    for (@a) jest specjalnie obudowany, aby uniknąć spłaszczenia tablicy. Pętla jest powtarzana nad indeksami tablicy.

  • Pod względem czytelności: #1.

  • Pod względem elastyczności: #1 / # 4 i # 5.

    #2 nie obsługuje elementów, które są fałszywe. #2 i # 3 są destrukcyjne.

 64
Author: ikegami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-14 12:22:47

Jeśli zależy Ci tylko na elementach @Array, Użyj:

for my $el (@Array) {
# ...
}

Lub

Jeśli wskaźniki mają znaczenie, użyj:

for my $i (0 .. $#Array) {
# ...
}

Lub od perl 5.12.1, możesz użyć:

while (my ($i, $el) = each @Array) {
# ...
}

Jeśli potrzebujesz zarówno elementu, jak i jego indeksu w ciele pętli, spodziewałbym się używając each aby być najszybszym, ale wtedy zrezygnujesz z kompatybilności z pre-5.12.1 perls.

Inny wzór niż te może być odpowiedni w pewnych okolicznościach.

 19
Author: Sinan Ünür,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-08 03:49:00

IMO, implementacja #1 jest typowa i jest krótka i idiomatyczna dla Perla przebija innych tylko za to. Porównanie tych trzech opcji może dać ci przynajmniej wgląd w szybkość.

 3
Author: JRFerguson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-07 19:03:48

1 zasadniczo różni się od 2 i 3, ponieważ pozostawia tablicę w takcie, podczas gdy pozostałe dwie pozostawiają ją pustą.

Powiedziałbym, że #3 jest dość zwariowany i prawdopodobnie mniej wydajny, więc zapomnij o tym.

Co pozostawia cię z #1 i # 2, i nie robią tego samego, więc jeden nie może być "lepszy" od drugiego. Jeśli tablica jest duża i nie musisz jej trzymać, ogólnie scope poradzi sobie z nią (ale zobacz uwaga), więc ogólnie , #1 jest nadal najczystsza i najprostsza metoda. Przesunięcie każdego elementu nie przyspieszy niczego. Nawet jeśli istnieje potrzeba uwolnienia tablicy z referencji, po prostu pójdę:

undef @Array;

Kiedy skończymy.

  • uwaga : podprogram zawierający zakres tablicy faktycznie zachowuje tablicę i ponownie używa przestrzeni następnym razem. ogólnie , powinno być dobrze (patrz komentarze).
 2
Author: delicateLatticeworkFever,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-07 20:33:24

W jednym wierszu, aby wydrukować element lub tablicę.

Print $ _ for (@array);

Notatka: pamiętaj, że $_ wewnętrznie odnosi się do elementu @array w pętli. Wszelkie zmiany wprowadzone w $_ będą odzwierciedlać w @ array; ex.

my @array = qw( 1 2 3 );
for (@array) {
        $_ = $_ *2 ;
}
print "@array";

Wyjście: 2 4 6

 0
Author: Sandeep_black,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-30 09:09:59

Najlepszy sposób decydowania o takich pytaniach, aby je porównać:

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,
});

I uruchamianie tego na perlu 5, wersji 24, subversion 1 (v5.24.1) zbudowanym dla x86_64-linux-gnu-thread-multi

Dostaję:

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)

Więc 'foreach (@Array)' jest około dwa razy szybszy od pozostałych. Wszystkie inne są bardzo podobne.

@ikegami zwraca również uwagę, że istnieje sporo różnic w tych parametrach innych niż prędkość.

 0
Author: G. Allen Morris III,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-01 11:53:58