2011-01-20 21 views
15

Ho una sezione nel mio codice dove so che avrò bisogno di un array, e so esattamente quanti elementi quell'array dovrà avere. Questa sezione di codice verrà ripetuta molto, quindi potrei ottenere dei grossi risparmi di tempo inizializzando quella matrice alla dimensione che so di aver bisogno e poi riempiendola vs semplicemente spingendo gli elementi in avanti (premendo sarebbe O (n) al contrario di riempire spazi già creati, che sarebbe O (1)).Posso inizializzare una matrice con una determinata dimensione in Perl?

Detto questo, non riesco a trovare alcun modo elegante di inizializzare un array per una determinata dimensione, e non ho idea del perché. So che posso fare:

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

per ottenere un array di 50 articolo, ma che sembra davvero brutto per me e mi sento come se ci deve essere un modo migliore. Idee?

+2

Niente di male con preallocazione di array, ma questo odora di prematura e micro-ottimizzazione. Perché pensi che 'push' è O (n)? – mob

+0

Non c'è tempo per trovare un collegamento in questo momento, ma per farla breve: il push di richiede il looping attraverso l'array per trovare l'ultimo spazio aperto (è il modo in cui normalmente viene implementato il push, comunque, anche se ora ci sto pensando, è per una lista collegata singolarmente piuttosto che una matrice normalmente). Stai dicendo che è implementato in modo diverso in Perl? – Eli

+6

Sì, è un po 'diverso. Gli elenchi di Perl sono array con un po 'di gioco sia nella parte anteriore che in quella posteriore. Inoltre conoscono le loro dimensioni, quindi sia 'push' che' unshift' sono generalmente O (1). Se il gioco si esaurisce, Perl ridistribuisce un nuovo array con più spazio. La riallocazione è un'operazione di tipo O (n), ma deve avvenire solo dopo ogni operazione di push di ~ log (n). – mob

risposta

13

Per essere onesti, la tua strada è perfettamente a posto, come è esplicitamente la modifica della dimensione della matrice: $#array = 49;;

+12

E se anche gli elementi devono essere inizializzati, usa 'my @ array = (0) x50' – slu

3

La tua strada è ottima, così come quella di DVK. Un modo per farlo in un singolo comando potrebbe essere:

@array = (0 .. 49);

Ma non sono sicuro che sia più elegante, dal momento che assegna un valore compreso tra 1 e 49 a ciascun elemento, ma è probabilmente più intuitivo capire per un programmatore non molto nella sintassi di Perl.

+2

-1 Il tuo modo è sbagliato ... Non stai preallando, hai solo 50 valori in una riga! – sebthebert

+3

@sebthebert, è proprio quello che ho detto. Si prega di leggere la parte sottostante il codice. – cbrandolino

5

Ogni volta che stai pensando di fare questo tipo di ottimizzazione, fai un po 'di profilazione! Il risultato potrebbe non essere quello che ti aspetti. Per esempio, ho usato il seguente script rapido per testare la teoria che pre-assegnazione della matrice è più veloce:

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

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

Che ha preso 2,13 secondi.

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

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

Sono occorsi 2,16 secondi (ho eseguito entrambi i test più volte). Quindi, in realtà, è più veloce lasciare che il comando perl allochi l'array come necessario.

Aggiornamento

Dopo aver apportato le modifiche suggerite dai ysth, i numeri fanno un po 'più senso: 2,27 secondi per il metodo "push", e 2.21 per la pre-assegnazione. Anche così, mi chiedevo se tale ottimizzazione potesse davvero risparmiare in qualsiasi momento (la differenza era solo di 0,06 secondi dopo 100.000 iterazioni).

+0

Interessante! Grazie! Tranne che non capisco come sia possibile ... – Eli

+0

@arr viene riutilizzato da una iterazione alla successiva; per forzarlo a non essere riutilizzato, dì "my $ arrref;" prima del ciclo esterno e "$ arrref = \ @ arr;" alla fine del ciclo esterno. – ysth

+0

Aggiornato la mia risposta per riflettere il suggerimento di ysth. Suppongo che sia un buon modo per ottenere un risultato più obiettivo, ma una cosa del genere dovrebbe essere fatta nell'uso del mondo reale? – Brian

11
  1. La prima regola di Optimization Club è che non si ottimizza.
  2. La seconda regola di Ottimizzazione Club è, si fa non Ottimizza senza misurare.

Misurare, misurare, misurare prima di andare e assumere che è possibile farlo più velocemente eliminando Perl. Perl sta facendo l'ottimizzazione dell'uso comune molto più a lungo di te. Fidati.

2

Invece di un uso specifico valore indefinito

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

preallocare potrebbe non aiutare molto con la velocità, ma potrebbe aiutare con il ritorno della memoria al sistema, se i pezzi assegnati sono abbastanza grandi

Problemi correlati