Was ist der sicherste Weg, durch die Tasten eines Perl-Hash iterieren?

stimmen
84

Wenn ich einen Perl Hash mit einem Bündel von (Schlüssel, Wert) -Paare haben, was ist die bevorzugte Methode der iteriert durch alle Schlüssel? Ich habe gehört , dass die Verwendung von eachMai in irgendeiner Weise unbeabsichtigte Nebenwirkungen haben. Also, das ist wahr, und ist einer der beiden folgenden Methoden am besten, oder gibt es einen besseren Weg?

# Method 1
while (my ($key, $value) = each(%hash)) {
    # Something
}

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}
Veröffentlicht am 06/08/2008 um 03:53
quelle vom benutzer
In anderen Sprachen...                            


9 antworten

stimmen
170

Als Faustregel ist es, die Funktion am besten zu Ihren Bedürfnissen zu nutzen.

Wenn Sie nur die Schlüssel wollen und nicht vorhaben , jemals lesen einen der Werte, mit den Tasten ():

foreach my $key (keys %hash) { ... }

Wenn Sie nur die Werte möchten, verwenden Sie Werte ():

foreach my $val (values %hash) { ... }

Wenn Sie die Schlüssel benötigen und die Werte, verwenden Sie each ():

keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }

Wenn Sie planen , die Schlüssel des Hash in irgendeiner Weise zu ändern , außer für den aktuellen Schlüssel während der Iteration zu löschen, dann müssen Sie nicht jede () verwenden. Zum Beispiel dieser Code eine neue Reihe von Großtasten mit verdoppelten Werten funktioniert gut mit den Tasten () zu erstellen:

%h = (a => 1, b => 2);

foreach my $k (keys %h)
{
  $h{uc $k} = $h{$k} * 2;
}

Erzeugen des erwarteten resultierenden hash:

(a => 1, A => 2, b => 2, B => 4)

Aber mit each (), das Gleiche zu tun:

%h = (a => 1, b => 2);

keys %h;
while(my($k, $v) = each %h)
{
  $h{uc $k} = $h{$k} * 2; # BAD IDEA!
}

falsche Ergebnisse in schwer zu sagen voraus Wege. Beispielsweise:

(a => 1, A => 2, b => 2, B => 8)

Dies ist jedoch sicher:

keys %h;
while(my($k, $v) = each %h)
{
  if(...)
  {
    delete $h{$k}; # This is safe
  }
}

All dies ist in der Perl-Dokumentation beschrieben:

% perldoc -f keys
% perldoc -f each
Beantwortet am 06/08/2008 um 14:22
quelle vom benutzer

stimmen
21

Eine Sache , die Sie beachten sollten bei der Verwendung eachist , dass es den Nebeneffekt der Zugabe von „Staat“ zu Ihrem Hash hat (der Hash hat sich daran zu erinnern , was die „nächste“ -Taste). Wenn Code wie der oben erzielte Schnipsel verwendet , die in einem Rutsch über die gesamte Hash laufen, ist dies in der Regel kein Problem. Sie werden jedoch in harten laufen Probleme aufzuspüren (ich spreche aus Erfahrung;), bei der Verwendung eachmit Anweisungen wie zusammen lastoder returnzum Verlassen der while ... eachSchleife , bevor Sie alle Schlüssel verarbeitet.

In diesem Fall wird der Hash erinnern , welche Tasten er bereits zurückgekehrt ist, und wenn Sie eachauf es das nächste Mal (vielleicht in einem totaly nicht verwandten Stück Code), wird es an dieser Stelle fortsetzen.

Beispiel:

my %hash = ( foo => 1, bar => 2, baz => 3, quux => 4 );

# find key 'baz'
while ( my ($k, $v) = each %hash ) {
    print "found key $k\n";
    last if $k eq 'baz'; # found it!
}

# later ...

print "the hash contains:\n";

# iterate over all keys:
while ( my ($k, $v) = each %hash ) {
    print "$k => $v\n";
}

Dieser Druck:

found key bar
found key baz
the hash contains:
quux => 4
foo => 1

Was Schlüssel „bar“ und baz passiert? "Sie sind immer noch da, aber die zweite eachbeginnt dort , wo die erste aufgehört hat , und stoppt , wenn das Ende des Hash erreicht, so dass wir sie nie in der zweiten Schleife sehen.

Beantwortet am 16/09/2008 um 00:37
quelle vom benutzer

stimmen
19

Der Ort , wo eachkönnen Sie Probleme verursacht , ist , dass es ein echter, nicht-scoped Iterator ist. Als Beispiel:

while ( my ($key,$val) = each %a_hash ) {
    print "$key => $val\n";
    last if $val; #exits loop when $val is true
}

# but "each" hasn't reset!!
while ( my ($key,$val) = each %a_hash ) {
    # continues where the last loop left off
    print "$key => $val\n";
}

Wenn Sie sicher sein müssen , dass eachalle Schlüssel und Werte bekommt, müssen Sie sicherstellen , dass Sie verwenden keysoder valueszuerst (wie das der Iterator setzt). Finden Sie in der Dokumentation zu .

Beantwortet am 16/09/2008 um 15:35
quelle vom benutzer

stimmen
13

die jede Syntax verwendet, wird den gesamten Satz von Tasten nicht auf einmal erzeugt werden. Dies kann wichtig sein, wenn Sie einen Tie-ed-Hash zu einer Datenbank mit Millionen von Zeilen verwenden. Sie wollen nicht auf einmal die gesamte Liste der Schlüssel zu generieren und erschöpfen Ihre physischen Speicher. In diesem Fall dient jeweils als ein Iterator während Schlüssel tatsächlich das gesamte Array erzeugt, bevor die Schleife beginnt.

Also, der einzige Ort, „jeder“ der realen Gebrauch ist, wenn der Hash sehr groß ist (im Vergleich zu dem Speicher verfügbar). Das ist wahrscheinlich nur geschehen, wenn der Hash selbst nicht im Speicher selbst nicht leben, wenn Sie ein Handheld-Datenerfassungsgerät oder etwas mit kleinen Speichern programmiert sind.

Wenn der Speicher ist kein Problem, in der Regel der Karte oder Schlüssel Paradigma ist das mehr prevelant und einfaches Paradigma zu lesen.

Beantwortet am 11/09/2008 um 23:04
quelle vom benutzer

stimmen
5

Ein paar verschiedenen Gedanken zu diesem Thema:

  1. Es gibt nichts , unsicher über eine der Hash - Iteratoren selbst. Was nicht sicher ist, den Schlüssel eines Hash - Modifikation , während Sie über es sind iterieren. (Es ist absolut sicher , um die Werte zu ändern.) Die einzige mögliche Nebeneffekt I heißt denken kann , die valuesAliasnamen zurückgibt , was bedeutet , dass sie zu modifizieren , wird der Inhalt des Hash ändern. Das ist von Entwurf aber möglicherweise nicht, was Sie unter Umständen möchten.
  2. Johns akzeptierte Antwort ist gut , mit einer Ausnahme: Die Dokumentation ist klar, dass es nicht sicher ist Schlüssel hinzufügen , während eines Hash - Iteration über. Es kann für einige Datensätze arbeiten , aber für andere nicht in Abhängigkeit von der Hash - Reihenfolge.
  3. Wie bereits erwähnte, ist es sicher durch den letzten Schlüssel zurückgegeben zu löschen each. Das ist nicht wahr für keysso eachist ein Iterator während keyskehrt eine Liste.
Beantwortet am 15/09/2008 um 22:36
quelle vom benutzer

stimmen
4

Ich benutze Methode immer 2 als auch. Der einzige Vorteil jeder Verwendung ist, wenn Sie gerade lesen (und nicht die Neuzuweisung) den Wert des Hash-Eintrag, dass Sie nicht ständig De-Referenzierung der Hash.

Beantwortet am 06/08/2008 um 05:04
quelle vom benutzer

stimmen
4

Ich kann von diesem gebissen, aber ich denke, dass es persönliche Präferenz ist. Ich kann keinen Hinweis in der Dokumentation zu jedem finden () als Schlüssel unterschiedlich ist () oder Werte () (andere als die offensichtlichen „kehren sie verschiedene Dinge“ zu beantworten. In der Tat die Dokumentation der Verwendung den gleichen Iterator angeben, und sie alle Rück aktuelle Liste Werte statt Kopien von ihnen, und dass der Hash-Modifikation während über sie iterieren jeden Anruf mit schlecht ist.

Alles, was gesagt, verwende ich fast immer Tasten (), um mich, weil es in der Regel mehr selbstdokumentiere ist selbst der Schlüssel des Wertes über den Hash zuzugreifen. Ich verwende gelegentlich Werte (), wenn der Wert ein Verweis auf eine große Struktur ist und der Schlüssel zu dem Hash wurde bereits in der Struktur gespeichert ist, wobei an diesem Punkt die Taste redundant ist, und ich brauche es nicht. Ich glaube, ich habe each () 2 mal in 10 Jahren von Perl-Programmierung verwendet und es war wahrscheinlich die falsche Wahl beide Male =)

Beantwortet am 06/08/2008 um 04:43
quelle vom benutzer

stimmen
1

Normalerweise verwende ich keysund ich kann ich das letzte Mal nicht denken verwendet oder eine Verwendung lesen each.

Vergessen Sie nicht über map, je nachdem , was Sie in der Schleife tun!

map { print "$_ => $hash{$_}\n" } keys %hash;
Beantwortet am 22/08/2008 um 16:31
quelle vom benutzer

stimmen
-2

Ich woudl sagen:

  1. Verwenden Sie, was am einfachsten lesen / verstehen für die meisten Menschen (so Schlüssel, in der Regel, ich würde behaupten)
  2. Verwenden Sie, was Sie konsequent throught die gesamte Code-Basis entscheiden.

Diese gibt 2 große Vorteile:

  1. Es ist einfacher „gemeinsamen“ Code zu erkennen, so dass Sie in Funktionen / methiods erneut Faktor.
  2. Es ist einfacher für zukünftige Entwickler zu erhalten.

Ich glaube nicht, es teurer ist Schlüssel über jedes zu verwenden, so dass keine Notwendigkeit für zwei verschiedene Konstrukte für die gleiche Sache in Ihrem Code.

Beantwortet am 20/12/2010 um 13:46
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more