在Perl中对哈希进行迭代会得到不同的结果



我的问题很简单。我必须从散列中打印一些键值对。我尝试了两种不同的方法:

方法A

#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 %dn", $prefix, $p1, $p2, $v;
printf "%s_up_%s %s %dn", $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 %dn", $prefix, $p1, $p2, $v;
printf "%s_up_%s %s %dn", $prefix, $p2, $p1, $v;
}
}

阅读代码时,我会说两个方法都得到了相同的结果,但在执行后,方法B得到了正确的结果,而法A只打印了两个元素(4行)。

在多次运行方法A之后,我可以看到每次执行时打印的元素都会发生变化。

有人知道这里发生了什么吗?

foreacheach一起使用是错误的

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

打印

c=>3c=>3

while代替foreach,我们得到了正确的行为。

这是错误的,可以从每个(我的重点)中看出

在列表上下文中对哈希调用时,返回一个2元素列表,该列表由哈希的下一个元素的键和值组成。

因此each迭代,并且由于foreach首先生成整个列表(要迭代),因此each以(明显)定义不清的方式在内部迭代;这可能表现出未定义的行为。我们最终得到了一个不正确的键值对列表,供foreach迭代(使用each内部形成)。

仔细阅读each页面,了解使用keysvalueseach的更多细节。


一个更有说服力的示例

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

在我的系统上打印

e=>5e=>5

使用while正确运行时,首先返回e => 5。所以我们得到了那双,两次。

(仍在试图找出原因两次…)

最新更新