it-swarm.com.de

Die beste Möglichkeit, ein Perl-Array zu durchlaufen

Welches ist die beste Implementierung (in Bezug auf Geschwindigkeit und Speicherauslastung) zum Durchlaufen eines Perl-Arrays? Gibt es einen besseren Weg? (@Array muss nicht beibehalten werden).

Implementierung 1

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

Implementierung 2

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

Implementierung 3

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

Implementierung 4

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

Implementierung 5

map { SubRoutine($_) } @Array ;
88
Jean
  • In Bezug auf die Geschwindigkeit: Nr. 1 und Nr. 4, in den meisten Fällen jedoch nicht viel.

    Sie könnten einen Benchmark schreiben, um zu bestätigen, aber ich vermute, dass Sie # 1 und # 4 etwas schneller finden werden, da die Iterationsarbeit in C statt in Perl ausgeführt wird und kein unnötiges Kopieren der Array-Elemente erfolgt. ($_ ist Alias ​​für das Element in # 1, aber # 2 und # 3 sind eigentlich copy die Skalare aus dem Array.)

    # 5 könnte ähnlich sein.

  • In Bezug auf den Speicherbedarf: Sie sind bis auf # 5 alle gleich.

    for (@a) hat ein spezielles Gehäuse, um eine Abflachung des Arrays zu vermeiden. Die Schleife durchläuft die Indizes des Arrays.

  • In Bezug auf die Lesbarkeit: # 1.

  • In Bezug auf Flexibilität: # 1/# 4 und # 5.

    Nummer 2 unterstützt keine falschen Elemente. # 2 und # 3 sind zerstörerisch.

67
ikegami

Wenn Sie sich nur für die Elemente von @Array interessieren, verwenden Sie:

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

oder 

Wenn die Indizes von Bedeutung sind, verwenden Sie:

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

Oder ab Perl 5.12.1 können Sie Folgendes verwenden:

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

Wenn Sie sowohl das Element als auch seinen Index im Hauptteil der Schleife benötigen, Ich würde erwarten mit each schnellster zu sein, aber dann Sie werden die Kompatibilität mit der Version 5.12.1 Perls aufgeben.

Ein anderes Muster als dieses kann unter bestimmten Umständen angemessen sein.

23
Sinan Ünür

IMO, Implementierung # 1 ist typisch und kurz und idiomatisch für Perl. Ein Benchmark der drei Auswahlmöglichkeiten bietet Ihnen zumindest Einblick in die Geschwindigkeit.

3
JRFerguson

1 unterscheidet sich wesentlich von 2 und 3, da es das Array in Takt lässt, während die anderen beiden es leer lassen.

Ich würde sagen, # 3 ist ziemlich verrückt und wahrscheinlich weniger effizient, also vergiss das.

Was Sie mit # 1 und # 2 belässt, und sie tun nicht dasselbe, also kann einer nicht "besser" sein als der andere. Wenn das Array groß ist und Sie es nicht behalten müssen, wird es mit generell behandelt (aber sieheNOTE), also allgemein, # 1 ist immer noch die klarste und einfachste Methode. Wenn Sie jedes Element ausschalten, wird nichts beschleunigt. Selbst wenn das Array von der Referenz befreit werden muss, gehe ich einfach:

undef @Array;

wenn fertig.

  • NOTE: Die Subroutine, die den Gültigkeitsbereich des Arrays enthält, behält das Array tatsächlich bei und verwendet beim nächsten Mal den Speicherplatz erneut. Im Allgemeinen sollte das in Ordnung sein (siehe Kommentare).

In einer Zeile, um das Element oder das Array zu drucken. 

$ _ for (@array) ausgeben;

HINWEIS: Denken Sie daran, dass $ _ sich intern auf das Element von @array in loop bezieht. Alle in $ _ vorgenommenen Änderungen werden in @array angezeigt. Ex. 

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

ausgabe: 2 4 6 

0
Sandeep_black

Der beste Weg, um Fragen wie diese zu bestimmen, um sie zu bewerten:

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

Und dies auf Perl 5, Version 24, Subversion 1 (v5.24.1) ausführen, das für x86_64-linux-gnu-thread-multi erstellt wurde

Ich bekomme:

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)

Das 'foreach (@Array)' ist also doppelt so schnell wie die anderen. Alle anderen sind sehr ähnlich.

@ikegami weist auch darauf hin, dass diese Implikationen einige andere Unterschiede als die Geschwindigkeit aufweisen.

0