La mejor manera de iterar a través de una matriz de Perl
¿Cuál es la mejor implementación(en términos de velocidad y uso de memoria) para iterar a través de una matriz de Perl? ¿Hay alguna manera mejor? (@Array
no será necesario conservarlo).
Aplicación 1
foreach (@Array)
{
SubRoutine($_);
}
Aplicación 2
while($Element=shift(@Array))
{
SubRoutine($Element);
}
Aplicación 3
while(scalar(@Array) !=0)
{
$Element=shift(@Array);
SubRoutine($Element);
}
Aplicación 4
for my $i (0 .. $#Array)
{
SubRoutine($Array[$i]);
}
Aplicación 5
map { SubRoutine($_) } @Array ;
6 answers
-
En términos de velocidad: #1 y #4, pero no por mucho en la mayoría de los casos.
Podría escribir un benchmark para confirmar, pero sospecho que encontrará que #1 y #4 son ligeramente más rápidos porque el trabajo de iteración se realiza en C en lugar de Perl, y no se produce una copia innecesaria de los elementos del array. (
$_
es aliased al elemento en #1, pero #2 y #3 en realidad copian los escalares de la matriz.)#5 podría ser similar.
-
En términos de uso de memoria: Todos son iguales excepto el número 5.
for (@a)
es especial-cased para evitar aplanar la matriz. El bucle itera sobre los índices de la matriz. En términos de legibilidad: #1.
-
En términos de flexibilidad: #1 / #4 y #5.
#2 no soporta elementos que son falsos. #2 y #3 son destructivos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-14 12:22:47
Si solo te importan los elementos de @Array
, usa:
for my $el (@Array) {
# ...
}
O
Si los índices son importantes, utilice:
for my $i (0 .. $#Array) {
# ...
}
O, a partir de perl
5.12.1, puede usar:
while (my ($i, $el) = each @Array) {
# ...
}
Si necesita tanto el elemento como su índice en el cuerpo del bucle, esperaría usar each
para ser el más rápido, pero entonces {[17] }estarás renunciando a la compatibilidad con pre - 5.12.1 perl
s.
Algún otro patrón que estos podría ser apropiado bajo ciertas circunstancias.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-08 03:49:00
IMO, la implementación #1 es típica y ser corta e idiomática para Perl supera a los demás solo por eso. Un punto de referencia de las tres opciones podría ofrecerle una idea de la velocidad, al menos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-07 19:03:48
1 es sustancialmente diferente de 2 y 3, ya que deja el array intacto, mientras que los otros dos lo dejan vacío.
Yo diría que #3 es bastante loco y probablemente menos eficiente, así que olvídalo.
Que te deja con #1 y #2, y no hacen lo mismo, así que uno no puede ser "mejor" que el otro. Si la matriz es grande y no necesita conservarla, generalmente el ámbito se ocupará de ella ( pero vea NOTA ), así que generalmente , #1 sigue siendo el método más claro y simple. Desplazar cada elemento no acelerará nada. Incluso si hay una necesidad de liberar el array de la referencia, simplemente iría:
undef @Array;
Cuando haya terminado.
- NOTA: La subrutina que contiene el alcance de la matriz en realidad mantiene la matriz y reutiliza el espacio la próxima vez. Generalmente , eso debería estar bien (ver comentarios).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-07 20:33:24
En una sola línea para imprimir el elemento o matriz.
Print _ _ for (@array);
NOTA: recuerde que internally_ se refiere internamente al elemento de @ array en bucle. Cualquier cambio realizado en $ _ se reflejará en @ array; ex.
my @array = qw( 1 2 3 );
for (@array) {
$_ = $_ *2 ;
}
print "@array";
Salida: 2 4 6
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-30 09:09:59
La mejor manera de decidir preguntas como esta para compararlas:
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,
});
Y ejecutando esto en perl 5, versión 24, subversion 1 (v5.24.1) construido para x86_64-linux-gnu-thread-multi
Obtengo:
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)
Así que el 'foreach (@Array)' es aproximadamente el doble de rápido que los otros. Todos los demás son muy similares.
@ikegami también señala que hay bastantes diferencias en estas implimentaciones aparte de la velocidad.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-01 11:53:58