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 ;
Author: Jean, 2012-05-07

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.

 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/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.

 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/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.

 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/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).
 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/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

 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/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.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-01 11:53:58