Quelle est la meilleure implémentation (en termes de vitesse et d’utilisation de la mémoire) pour une itération dans un tableau Perl? Y a-t-il une meilleure façon? (@Array
n'a pas besoin d'être conservé).
foreach (@Array)
{
SubRoutine($_);
}
while($Element=shift(@Array))
{
SubRoutine($Element);
}
while(scalar(@Array) !=0)
{
$Element=shift(@Array);
SubRoutine($Element);
}
for my $i (0 .. $#Array)
{
SubRoutine($Array[$i]);
}
map { SubRoutine($_) } @Array ;
En termes de vitesse: n ° 1 et n ° 4, mais pas beaucoup dans la plupart des cas.
Vous pouvez écrire un point de repère pour confirmer, mais je suppose que vous constaterez que les n ° 1 et 4 sont légèrement plus rapides, car le travail d'itération est effectué en C au lieu de Perl, et aucune copie inutile des éléments du tableau ne se produit. ($_
est aliasé de l'élément dans # 1, mais # 2 et # 3 réellement copie les scalaires du tableau.)
# 5 pourrait être similaire.
En termes d’utilisation de la mémoire: ils sont tous identiques, à l’exception du n ° 5.
for (@a)
est spécialement conçu pour éviter d’aplatir le tableau. La boucle itère sur les index du tableau.
En termes de lisibilité: # 1.
En termes de flexibilité: n ° 1/n ° 4 et n ° 5.
# 2 ne supporte pas les éléments qui sont faux. Les n ° 2 et n ° 3 sont destructeurs.
Si vous ne vous souciez que des éléments de @Array
, utilisez:
for my $el (@Array) {
# ...
}
ou
Si les indices sont importants, utilisez:
for my $i (0 .. $#Array) {
# ...
}
Ou, à partir de la version Perl
5.12.1, vous pouvez utiliser:
while (my ($i, $el) = each @Array) {
# ...
}
Si vous avez besoin à la fois de l'élément et de son index dans le corps de la boucle, Je m'attendrais en utilisant each
être le plus rapide, mais alors vous abandonnerez la compatibilité avec les Perl
s antérieures à la 5.12.1.
Une autre configuration que celles-ci pourrait être appropriée dans certaines circonstances.
OMI, la mise en œuvre n ° 1 est typique et être court et idiomatique pour Perl l'emporte sur les autres pour cela uniquement. Un repère des trois choix pourrait vous donner un aperçu de la vitesse, au moins.
1 est sensiblement différent de 2 et 3, car il laisse le tableau intact, alors que les deux autres le laissent vide.
Je dirais que le n ° 3 est assez farfelu et probablement moins efficace, alors oubliez ça.
Ce qui vous laisse avec # 1 et # 2, et ils ne font pas la même chose, donc on ne peut pas être "meilleur" que l'autre. Si le tableau est grand et que vous n'avez pas besoin de le conserver, la portée de généralement sera traitée (mais voirNOTE), donc généralement, # 1 reste la méthode la plus claire et la plus simple. Décaler chaque élément n'accélère rien. Même s'il est nécessaire de libérer le tableau de la référence, je voudrais simplement aller:
undef @Array;
lorsque vous avez terminé.
En une seule ligne pour imprimer l'élément ou le tableau.
print $ _ for (@array);
NOTE: rappelez-vous que $ _ fait référence en interne à l'élément de @array en boucle. Toute modification apportée dans $ _ sera reflétée dans @array; ex.
my @array = qw( 1 2 3 );
for (@array) {
$_ = $_ *2 ;
}
print "@array";
sortie: 2 4 6
La meilleure façon de décider de telles questions pour les comparer:
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,
});
Et ceci sur Perl 5, version 24, Subversion 1 (v5.24.1) construit pour x86_64-linux-gnu-thread-multi
Je reçois:
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)
Donc, 'foreach (@Array)' est environ deux fois plus rapide que les autres. Tous les autres sont très similaires.
@ikegami fait également remarquer qu'il existe de nombreuses différences dans ces implémentations autres que la vitesse.