2011-01-20 10 views
15

Tengo una sección en mi código donde sé que necesitaré una matriz, y sé exactamente cuántos elementos necesitará esa matriz. Esta sección de código se repetirá mucho, por lo que podría obtener un gran ahorro de tiempo inicializando primero ese conjunto al tamaño que sé que necesitará y luego llenándolo solo presionando ítems (presionar sería O (n) en lugar de llenar espacios ya creados, que serían O (1)).¿Puedo inicializar una matriz a un tamaño dado en Perl?

Dicho esto, parece que no puedo encontrar ninguna forma elegante de inicializar una matriz a un tamaño determinado, y no tengo ni idea de por qué. Sé que puedo hacer:

my @array; $array[49] =0;

para obtener una matriz 50 artículo, pero que se ve muy feo para mí y me siento como si tiene que haber una mejor manera. Ideas?

+2

No hay nada malo con arreglos preasignados, pero esto huele a una optimización prematura y micro-optimización. ¿Por qué crees que 'push' es O (n)? – mob

+0

No hay tiempo para encontrar un enlace en este momento, pero larga historia corta: empujando requiere pasar por la matriz para encontrar el último espacio abierto (de todas formas, así es como se implementa habitualmente, aunque ahora que estoy pensando en eso, eso para una lista individualmente vinculada en lugar de una matriz normalmente). ¿Estás diciendo que se implementó de manera diferente en Perl? – Eli

+6

Sí, es un poco diferente. Las listas Perl son matrices con cierta holgura tanto en la parte frontal como posterior. También conocen su tamaño, por lo que tanto 'push' como' unshift' son generalmente O (1). Si la holgura se agota, Perl reasignará una nueva matriz con más espacio. La reasignación es una operación O (n) pero solo tiene que suceder después de cada ~ log (n) operaciones de inserción. – mob

Respuesta

13

Para ser honesto, su camino está perfectamente bien, ya que está cambiando explícitamente el tamaño de la matriz: $#array = 49;;

+12

Y si los elementos necesitan ser inicializados también, use 'my @ array = (0) x50' – slu

3

Su camino es excelente, al igual que DVK. Una forma de hacerlo en un solo comando podría ser:

@array = (0 .. 49);

Pero no estoy seguro si es más elegante, ya que asigna un valor entre 1 y 49 a cada elemento, pero probablemente sea más intuitivo para un programador que no tenga mucha sintaxis.

+2

-1 Su camino es malo ... No está preasignando, ¡simplemente establece 50 valores en una línea! – sebthebert

+3

@sebthebert, eso es exactamente lo que dije. Por favor, lea la parte debajo del código. – cbrandolino

5

Cuando esté pensando en hacer este tipo de optimización, ¡haga algunos perfiles! El resultado puede no ser lo que esperas. Por ejemplo, he utilizado la siguiente secuencia de comandos rápida para probar su teoría de que la pre-asignación de la matriz es más rápido:

for (my $loops = 0; $loops < 100000; $loops++) 
{ 
    my @arr; 

    for (my $foo = 0; $foo < 50; $foo++) { 
     push @arr, 'bar'; 
    } 
} 

Eso tomó 2.13 segundos.

for (my $loops = 0; $loops < 100000; $loops++) 
{ 
    my @arr; 
    $arr[49] = 0; 

    for (my $foo = 0; $foo < 50; $foo++) { 
     $arr[$foo] = 'bar'; 
    } 
} 

Eso demoró 2,16 segundos (realicé ambas pruebas varias veces). Así que en realidad termina siendo más rápido para dejar que Perl maneje la asignación de la matriz según sea necesario.

actualización

Tras realizar los cambios sugeridos por ysth, los números hacen un poco más de sentido: 2,27 segundos para el método de "empuje" y 2.21 de preasignación. Aun así, me pregunto si tal optimización realmente ahorraría algún tiempo (la diferencia fue de solo 0.06 segundos después de 100,000 iteraciones).

+0

¡Interesante! ¡Gracias! Excepto que no entiendo cómo es posible ... – Eli

+0

@arr se reutiliza de una iteración a la siguiente; para forzar que no se reutilice, diga 'my $ arrref;' antes del bucle externo y '$ arrref = \ @ arr;' al final del bucle externo. – ysth

+0

Actualicé mi respuesta para reflejar la sugerencia de ysth. Supongo que es una buena manera de obtener un resultado más objetivo, pero ¿se haría algo así en el uso del mundo real? – Brian

11
  1. La primera regla del Club de optimización es que usted no optimiza.
  2. La segunda regla del Club de optimización es, usted no Optimizar sin medir.

Mida, mida, mida antes de ir y suponga que puede hacerlo más rápido falsificando Perl. Perl ha estado optimizando el uso común mucho más tiempo que tú. Confía en ello.

2

En lugar de un uso determinado valor undef

my @array; 
$array[49] = undef; 
1

La preasignación podría no ayuda mucho con la velocidad, pero podría ayudar a devolver la memoria para el sistema si los trozos asignados son lo suficientemente grandes

Cuestiones relacionadas