2009-07-14 3 views
6

Ho un semplice script che cerca di conoscere gli hash in Perl.Perché la Perl() non esegue iterate attraverso l'intero hash la seconda volta?

#!/usr/bin/perl 

my %set = (
    -a => 'aaa', 
    -b => 'bbb', 
    -c => 'ccc', 
    -d => 'ddd', 
    -e => 'eee', 
    -f => 'fff', 
    -g => 'ggg' 
); 

print "Iterate up to ggg...\n"; 
while (my ($key, $val) = each %set) { 
    print "$key -> $val \n"; 
    last if ($val eq 'ggg'); 
} 
print "\n"; 

print "Iterate All...\n"; 
while (my ($key, $val) = each %set) { 
    print "$key -> $val \n"; 
} 
print "\n"; 

Sono sorpreso dall'uscita: -

Iterate upto ggg... 
-a -> aaa 
-c -> ccc 
-g -> ggg 

Iterate All... 
-f -> fff 
-e -> eee 
-d -> ddd 
-b -> bbb 

Capisco che le chiavi sono hash quindi la prima uscita può essere 'n' elementi a seconda l'ordinamento interno. Ma perché non riesco a ripetere l'array in seguito? Cosa c'è che non va ?

Grazie,

risposta

18

each utilizza un puntatore associato con l'hash per tenere traccia di iterazione. Non sa che il primo è diverso dal secondo ciclo while e mantiene lo stesso puntatore tra di loro.

La maggior parte delle persone evitare each per questo (e altri) motivi, optando invece per keys:

for my $key (keys %hash){ 
    say "$key => $hash{$key}"; 
} 

Questo consente di controllare l'ordine di iterazione, così:

for my $key (sort keys %hash){ 
    say "$key => $hash{$key}"; 
} 

Comunque , se hai intenzione di terminare il ciclo in anticipo, evita each.

BTW, i sostenitori della programmazione funzionale dovrebbero cogliere l'occasione per sottolineare gli svantaggi dello stato nascosto. Ciò che appare come un'operazione senza stato ("loop over each pair in a table") è in realtà abbastanza statico.

+0

Grazie. A proposito, è possibile resettare "ciascuno" all'inizio? –

+0

"% hash =% hash" sembra funzionare. – jrockway

+6

(perlfaq4 suggerisce di chiamare "chiavi" sull'hash nel contesto vuoto. Ciò potrebbe evitare una copia non necessaria.) – jrockway

10

è possibile leggere il perldoc su ciascun

perldoc -f each 

Quando l'hash è stato letto interamente, un array null è restituito nel contesto di lista (che quando viene assegnato produce un falso (0) valore), e " undef "in contesto scalare. La prossima chiamata a "ciascuno" dopo avvierà di nuovo l'iterazione. C'è un sin- iteratore per ogni hash, condiviso da tutte le chiamate di funzione "ciascuna", "chiavi" e "valori" nel programma; può essere resettato da leggendo tutti gli elementi dall'hash, o valutando "chiavi HASH" o "valori HASH".

conseguenza, è possibile utilizzare i tasti% fissato nel codice per scorrere di nuovo (a causa di voi "ultimo" dichiarazione)

print "Iterate upto ggg...\n"; 
while (my ($key, $val) = each %set) { 
    print "$key -> $val \n"; 
    last if ($val eq 'ggg'); 
} 
print "\n"; 
keys %set; 
print "Iterate All...\n"; 
while (my ($key, $val) = each %set) { 
    print "$key -> $val \n"; 
} 
print "\n";