2009-07-14 6 views
6

J'ai un script simple essayant d'apprendre des hashs dans Perl.Pourquoi Perl() ne parcourt-il pas tout le hachage une seconde fois?

#!/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"; 

Je suis surpris par la sortie: -

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

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

Je comprends que les clés sont donc la première hachés sortie peut être des éléments « n » en fonction de l'ordre interne. Mais pourquoi ne suis-je pas capable de simplement boucler le tableau après? Qu'est-ce qui ne va pas ?

Merci,

Répondre

18

each utilise un pointeur associé au hachage de garder une trace de l'itération. Il ne sait pas que le premier moment est différent de la deuxième boucle while, et il garde le même pointeur entre eux.

La plupart des gens évitent each pour cela (et d'autres) raisons, au lieu d'opter pour keys:

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

Cela vous permet de contrôler l'ordre d'itération, ainsi:

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

Quoi qu'il en soit , si vous voulez terminer la boucle tôt, évitez each. BTW, les défenseurs de la programmation fonctionnelle devraient profiter de cette occasion pour souligner les inconvénients de l'état caché. Ce qui ressemble à une opération sans état ("boucle sur chaque paire dans une table") est en fait assez dynamique.

+0

Merci. BTW, est-il possible de réinitialiser «chaque» retour au début? –

+0

"% hash =% hash" semble fonctionner. – jrockway

+6

(perlfaq4 suggère d'appeler des "clés" sur le hachage dans un contexte vide, ce qui pourrait éviter une copie inutile.) – jrockway

10

vous pouvez lire le perldoc sur chaque

perldoc -f each 

Lorsque le hachage est entièrement lu, un tableau NULL est retourné dans le contexte de la liste (qui, lorsqu'il est attribué produit un faux (0) valeur ), et " undef "dans un contexte scalaire. L'appel suivant à "chacun" après cela recommencera à répéter. Il y a un itérateur pour chaque hachage, partagé par tous les appels de fonction "each", "keys" et "values" dans le programme; il peut être réinitialisé par en lisant tous les éléments du hachage, ou en évaluant "keys HASH" ou "values ​​HASH".

Par conséquent, vous pouvez utiliser les touches% jeu dans votre code pour itérer à nouveau (en raison de la déclaration que vous « dernier »)

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"; 
Questions connexes