我的问题很简单。我必须从哈希中打印一些键值对。我尝试了两种不同的方法:
方法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 %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 后,我可以看到打印的元素会改变每次执行。
有人知道这里发生了什么吗?
答案 0 :(得分:2)
foreach
与each
的使用是错误的
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
页面,了解使用keys
,values
和each
的其他细微之处。
一个更有说服力的例子
perl -wE'@h{("a".."f")} = (1..6); for (($k, $v) = each %h) { say "$k => $v" }'
在我的系统上打印
e => 5 e => 5
使用while
正确运行后,{em>首先会返回e => 5
对。所以我们两次得到那对。
(仍然试图找出为什么两次...... )