2017-10-18 58 views
1

我的問題很簡單。我必須從散列中打印一些鍵值對。我嘗試了兩種不同的方法:不同的結果迭代在Perl中的散列

方法

#Fill hash from file ($fh has been defined previously) 

while(my $line = <$fh>) { 
    $counter{$line}++; 
} 

foreach (my($k, $v) = each %counter){ 
    my ($p1, $p2) = split(/$;/o, $k); 

    chomp $p2; 

    if($v > 0){ 
     printf "%s_down_%s %s %d\n", $prefix, $p1, $p2, $v; 
     printf "%s_up_%s %s %d\n", $prefix, $p2, $p1, $v; 
    } 
} 

方法B

#Fill hash from file ($fh has been defined previously) 

while(my $line = <$fh>) { 
    $counter{$line}++; 
} 

foreach $k (keys %counter) { 
    my ($p1, $p2) = split(/$;/o, $k); 
    my $v = $counter{$p1,$p2}; 

    chomp $p2; 

    if($v > 0){ 
     printf "%s_down_%s %s %d\n", $prefix, $p1, $p2, $v; 
     printf "%s_up_%s %s %d\n", $prefix, $p2, $p1, $v; 
    } 
} 

讀碼,我會說這兩種方法獲得相同的結果,但是,執行後它,方法B,得到正確的結果和方法A只印兩個元素( 4行)。

運行方法A幾次後,我可以看到打印的元素改變了每次執行。

有人知道這裏發生了什麼嗎?

回答

2

each使用的foreach是錯誤的

perl -wE'%h=(a=>1,b=>2,c=>3); for (($k, $v) = each %h) { say "$k => $v" }' 

打印

 
c => 3 
c => 3 

隨着while而不是foreach我們得到正確的行爲。

,這是錯誤可以從each(我的重點)可以看出

當呼籲在列表上下文中的哈希,返回一個包含了下一個元素鍵和值的2元素的列表的散列。

所以each迭代,並且因爲foreach首先產生整個列表(遍歷)each被製成在(明確)定義不清的方式在內部循環;這可能表現出未定義的行爲。我們最終得到一個foreach的鍵值對的錯誤列表進行迭代(使用each內部形成)。

請仔細閱讀each頁面以瞭解使用keysvalueseach的更多細節。


一個更有力的例子在我的系統上

perl -wE'@h{("a".."f")} = (1..6); for (($k, $v) = each %h) { say "$k => $v" }' 

打印

 
e => 5 
e => 5 

當正常運行與whilee => 5對返回第一。所以我們得到那一對,兩次。

仍在試圖弄清楚爲什麼兩次...

+0

@IvánRodríguezTorres更新了答案,無論是通過編輯第一個例子和說明,並添加一個更好的例子。結果當然是一樣的:「for」是錯誤的,需要使用'while'。但是,爲了解釋使用'for'時的行爲,還有更多。感謝您的歸屬。 – zdim

+1

你的回答非常明確,一如既往。謝謝。 –

+0

@IvánRodríguezTorres很高興幫助並感謝您的評論。很高興與你互動:) – zdim