Co je to nejbezpečnější způsob, jak iterovat klíče Perl hash?

hlasů
84

Mám-li Perl hash s partou (klíč, hodnota) párech, co je preferovanou metodou iterace všechny klíče? Slyšel jsem, že použití eachmůže být v některých způsobem mít nezamýšlené vedlejší účinky. Ano, je to pravda, a je jedním ze dvou následujících způsobů nejlepší, nebo existuje lepší způsob?

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

# Method 2
foreach my $key (keys(%hash)) {
    # Something
}
Položena 06/08/2008 v 03:53
zdroj uživatelem
V jiných jazycích...                            


9 odpovědí

hlasů
170

Pravidlem je používat funkci nejvíce vyhovuje vašim potřebám.

Pokud chcete jen klíče a neplánují vůbec přečíst některou z hodnot pomocí tlačítek ():

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

Pokud chcete jen hodnoty, použijte hodnoty ():

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

Pokud budete potřebovat klíče a hodnoty, použijte each ():

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

Pokud máte v plánu změnit klíče hash v žádném případě výjimkou pro vymazání aktuální klíč během iterace, pak nesmíte používat každý (). Například tento kód vytvořit novou sadu velkých kláves se zdvojenými hodnotami funguje pomocí tlačítek ():

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

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

produkující očekávaný výsledný hash:

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

Ale za použití each () a to samé:

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

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

produkuje nesprávné výsledky v těžko předvídat způsoby. Například:

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

To je však v bezpečí:

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

To vše je popsáno v dokumentaci perl:

% perldoc -f keys
% perldoc -f each
Odpovězeno 06/08/2008 v 14:22
zdroj uživatelem

hlasů
21

Jedna věc, kterou byste měli být vědomi při použití eachje to, že má vedlejší účinky přidávání „stav“ k vaší hash (hash musí mít na paměti, co je „další“ klíč). Při použití kódu jako úryvcích výše vyslaných, který iteraci přes celý hash v jednom kroku, je to obvykle není problém. Nicméně, bude se dostanete do těžké vystopovat problémy (mluvím z vlastní zkušenosti), při použití eachspolečně s prohlášeními, jako je lastnebo returnna výstupu ze while ... eachsmyčky, než jste zpracovány všechny klíče.

V tomto případě bude hash pamatovat, které klíče již vrátila, a když použijete eachna to příště (snad v totálně nepříbuzné kus kódu) bude pokračovat v této pozici.

Příklad:

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";
}

Vytiskne:

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

Co se stalo s tlačítky „bar“ a Baz "? Jsou tam pořád, ale druhý eachzačíná tam, kde první skončil, a zastaví se, jakmile dosáhne konce hash, takže jsme nikdy vidět ve druhé smyčce.

Odpovězeno 16/09/2008 v 00:37
zdroj uživatelem

hlasů
19

Místem, kde eachmůže způsobit problémy, je, že je to pravda, ne na procesor iterátor. Jako příklad:

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";
}

Pokud potřebujete mít jistotu, že eachdostane všechny klíče a hodnoty, je třeba se ujistit, že použití keysnebo valuesprvní (jako že obnoví iterátor). Podívejte se na dokumentaci pro každého .

Odpovězeno 16/09/2008 v 15:35
zdroj uživatelem

hlasů
13

Použití každé syntax zabrání kompletní sadu klíčů od generování najednou. To může být důležité, pokud používáte tie-ed hash databázi s miliony řádků. Nechcete generovat celý seznam kláves najednou, a vyčerpat svou fyzickou paměť. V tomto případě každý slouží jako iterátor, zatímco klávesy skutečně generuje celého pole před začátkem smyčka.

Takže jediné místo, kde „každý“ je skutečné využití je, když hash je velmi velký (oproti dostupné paměti). To je jen pravděpodobné, že se stane, když je hash sám nežije v paměti sám o sobě, pokud jste programování ruční sběr dat zařízení nebo něco s malou pamětí.

Pokud mi paměť není problém, obvykle mapy nebo klíče paradigma je více prevelant a čitelnější paradigma.

Odpovězeno 11/09/2008 v 23:04
zdroj uživatelem

hlasů
5

Několik různé myšlenky na toto téma:

  1. Na tom není nic nebezpečné o některý z samotných hash iterátory. Co je nebezpečné, je úpravou klíče hash, zatímco vy iterace nad ním. (Je to naprosto bezpečné pro úpravu hodnoty.) Jedinou potenciální vedlejší účinek mě napadá, je, že valuesse vrací aliasů, což znamená, že jejich změna bude měnit obsah hash. Toto chování je záměrné, ale nemusí být to, co chcete, za určitých okolností.
  2. Johnův přijímanou odpovědí je dobrá s jednou výjimkou: v dokumentaci je jasné, že to není bezpečné pro přidání klíče, zatímco iterace přes hash. To může pracovat pro některé datové sady, ale selžou pro ostatní v závislosti na hash pořadí.
  3. Jak již bylo řečeno, je bezpečné odstranit poslední klíč vrácené each. Je to není pravda, pro keysjak eachje iterátor, když keysse vrátí seznam.
Odpovězeno 15/09/2008 v 22:36
zdroj uživatelem

hlasů
4

Vždycky jsem použít metodu 2, jakož. Jedinou výhodou použití každé z nich je, pokud jste jen čtení (spíše než re-přiřazování) na hodnotu položky hash, nejste neustále de-odkazování hash.

Odpovězeno 06/08/2008 v 05:04
zdroj uživatelem

hlasů
4

Mohu dostat pokousal tento jeden, ale myslím, že je to osobní preference. Nemohu najít žádnou zmínku v Dokumentech ke každému () je odlišný od klíčů () nebo hodnoty () (jinými, než je zřejmé, „vracejí různé věci“ odpověď. Ve skutečnosti docs státě užívání stejné iterace a všichni návrat skutečných hodnot seznam namísto jejich kopie, a to úpravou hash, zatímco iterace nad ním pomocí libovolného volání je špatné.

Vším, co řekl, jsem téměř vždy použít klíče (), protože pro mě to je obvykle více self dokumentování přístup hodnotu s klíčem přes samotný hash. Občas použít hodnoty (), když hodnota je odkaz na velkou strukturou a klíč k hash byl již uložen ve struktuře, na kterém místě je klíč nadbytečné a nepotřebuji to. Myslím, že jsem používal každý () 2 krát za 10 let programování v jazyce Perl a to byl pravděpodobně špatný výběr v obou případech =)

Odpovězeno 06/08/2008 v 04:43
zdroj uživatelem

hlasů
1

I obvykle používají keys, a já si nemyslím, že v poslední době jsem použil nebo číst využití each.

Nezapomeňte na map, v závislosti na tom, co děláte ve smyčce!

map { print "$_ => $hash{$_}\n" } keys %hash;
Odpovězeno 22/08/2008 v 16:31
zdroj uživatelem

hlasů
-2

I woudl říci:

  1. Použití bez ohledu na to nejjednodušší číst / pochopení pro většinu lidí (tak klíče, obvykle bych argumentovat)
  2. Použití cokoliv rozhodnout konzistentně přes celou základnu kódu.

Tato vzniku 2 hlavní výhody:

  1. Je to jednodušší, aby na místě „obyčejný“ kód, takže můžete re-faktor do funkce / methiods.
  2. Je to jednodušší pro budoucí vývojáře k udržení.

Nemyslím si, že je to dražší, pomocí kláves přes sebe, takže není třeba pro dva různé konstrukty pro stejnou věc ve vašem kódu.

Odpovězeno 20/12/2010 v 13:46
zdroj uživatelem

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