Welches ist die beste Implementierung (in Bezug auf Geschwindigkeit und Speichernutzung) für die Iteration durch ein Perl-Array? 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 ;
map
Antworten:
In Bezug auf die Geschwindigkeit: # 1 und # 4, aber in den meisten Fällen nicht viel.
Sie könnten einen Benchmark schreiben, um dies zu bestätigen, aber ich vermute, Sie werden feststellen, dass Nr. 1 und Nr. 4 etwas schneller sind, da die Iterationsarbeit in C anstelle von Perl ausgeführt wird und kein unnötiges Kopieren der Array-Elemente erfolgt. (
$_
Wird aliased in # 1, zu dem Elemente , aber # 2 und # 3 tatsächlich kopiert die Skalare aus dem Array.)# 5 könnte ähnlich sein.
In Bezug auf die Speichernutzung: Sie sind bis auf # 5 alle gleich.
for (@a)
ist ein spezielles Gehäuse, um ein Abflachen 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.
# 2 unterstützt keine Elemente, die falsch sind. # 2 und # 3 sind destruktiv.
quelle
my @todo = $root; while (@todo) { my $node = shift; ...; push @todo, ...; ...; }
Wenn Sie sich nur für die Elemente von interessieren
@Array
, verwenden Sie:oder
Wenn die Indizes wichtig sind, verwenden Sie:
Oder, wie es von
perl
5.12.1, können Sie:Wenn Sie sowohl das Element als auch seinen Index im Hauptteil der Schleife benötigen,
Ich würde erwartenmiteach
am schnellsten sein, aber dannSie werden die Kompatibilität mit Pre-5.12.1 aufgebenperl
.Ein anderes Muster als dieses kann unter bestimmten Umständen angemessen sein.
quelle
each
, dass das am langsamsten ist. Es erledigt die ganze Arbeit der anderen abzüglich eines Alias plus einer Listenzuweisung, zwei skalaren Kopien und zwei skalaren Löschungen.for
Iterieren über Indizes eines Arrays und 20% schneller beim Iterieren über die Indizes einer Array-Referenz (ich greife$array->[$i]
im Body zu) über die Verwendungeach
in Verbindung mitwhile
.IMO, Implementierung Nr. 1 ist typisch und kurz und idiomatisch für Perl zu sein, übertrumpft die anderen allein dafür. Ein Benchmark der drei Auswahlmöglichkeiten bietet Ihnen möglicherweise zumindest einen Einblick in die Geschwindigkeit.
quelle
1 unterscheidet sich wesentlich von 2 und 3, da das Array intakt bleibt, während die beiden anderen 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 nicht das Gleiche tun, so dass einer nicht "besser" sein kann als der andere. Wenn das Array groß ist und Sie es nicht behalten müssen, wird es im Allgemeinen vom Gültigkeitsbereich behandelt ( siehe HINWEIS ). Daher ist # 1 im Allgemeinen immer noch die klarste und einfachste Methode. Das Ausschalten jedes Elements beschleunigt nichts. Selbst wenn das Array von der Referenz befreit werden muss, würde ich einfach gehen:
wenn fertig.
quelle
@Array = ();
gibt das zugrunde liegende Array nicht frei. Das würde nicht einmal aus dem Rahmen gehen. Wenn Sie das zugrunde liegende Array freigeben möchten, müssen Sie es verwendenundef @Array;
.perl -MDevel::Peek -e'my @a; Dump(\@a,1); @a=qw( a b c ); Dump(\@a,1); @a=(); Dump(\@a,1); undef @a; Dump(\@a,1);' 2>&1 | grep ARRAY
()
vsundef
, aber wenn das Verlassen des Bereichs nicht den Speicher freigibt , der von einem lokalen Array in diesem Bereich verwendet wird, macht das Perl dann nicht zu einer undichten Katastrophe? Das kann nicht wahr sein.In einer Zeile, um das Element oder Array zu drucken.
print $ _ for (@array);
HINWEIS: Denken Sie daran, dass $ _ intern auf das Element von @array in loop verweist. Alle in $ _ vorgenommenen Änderungen werden in @array angezeigt. Ex.
Ausgabe: 2 4 6
quelle
Der beste Weg, um Fragen wie diese zu entscheiden, um sie zu bewerten:
Und dies auf Perl 5, Version 24, Subversion 1 (v5.24.1), ausgeführt für x86_64-linux-gnu-thread-multi
Ich bekomme:
Das 'foreach (@Array)' ist also ungefähr doppelt so schnell wie die anderen. Alle anderen sind sehr ähnlich.
@ikegami weist auch darauf hin, dass es bei diesen Implikationen außer der Geschwindigkeit einige Unterschiede gibt.
quelle
$index < $#array
sollte eigentlich sein,$index <= $#array
weil$#array
nicht die Länge des Arrays, sondern der letzte Index davon ist.