在Perl中迭代哈希的不同结果

时间:2017-10-18 19:31:48

标签: perl loops foreach

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

方法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 后,我可以看到打印的元素会改变每次执行。

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

1 个答案:

答案 0 :(得分:2)

foreacheach的使用是错误的

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

使用while正确运行后,{em>首先会返回e => 5对。所以我们两次得到那对。

仍然试图找出为什么两次......