Perl:在条件为

时间:2019-05-15 17:27:04

标签: perl while-loop grep

我面临与while条件有关的问题。 我的简单哈希:

my %ConnectionsIP = (
                '10.130.20.21' => 0,
                '10.130.20.22' => 0,
                '10.130.20.23' => 0,
                '10.130.20.24' => 0
            );

以下代码符合我的预期。

my $i = 0;
while (grep { $ConnectionsIP{$_} eq '0' } keys %ConnectionsIP){
    while ((my $key, my $value) = each (%ConnectionsIP)){
         print "KEY: $key, VAL: $value\n";
         $ConnectionsIP{$key} = $i++;
         next;
    }
}

在执行期间,每对(键,值)均正确显示。问题是第二个条件内的下一个grep:

my $i = 0;
while (grep { $ConnectionsIP{$_} eq '0' } keys %ConnectionsIP){
    while ((my $key, my $value) = each (%ConnectionsIP)){
         print "KEY: $key, VAL: $value\n";
         $ConnectionsIP{$key} = $i++;

         if (grep { $ConnectionsIP{$_} eq '1' } keys %ConnectionsIP){
             print "I have 1!\n";
             sleep 10;
         }
         next;
    }
}

在执行第二个代码期间,仍然打印具有增加值的相同键。这是什么原因呢?感谢您的反馈和解决方案:)

1 个答案:

答案 0 :(得分:4)

each充满了危险。每个哈希都有自己的迭代器。它用于eachkeysvalues之类的东西。

each(%ConnectionsIP)反复遍历%ConnectionsIP中的每一对,一次返回一个键/值对。它使用%ConnectionsIP的迭代器来记住它在哪里。

keys %ConnectionsIP遍历%ConnectionsIP的所有键,并将它们全部作为数组返回。这样, 它将重置迭代器

  

每个哈希或数组都有自己的内部迭代器,每个迭代器,键和值均可对其进行访问。如前所述,当迭代器到达末尾时,它会隐式重置。可以通过在哈希或数组上调用键或值来显式重置它。如果在迭代时添加或删除哈希的元素,则对迭代器的影响是不确定的;

my $i = 0;
while (grep { $ConnectionsIP{$_} eq '0' } keys %ConnectionsIP){
    while ((my $key, my $value) = each (%ConnectionsIP)){
         print "KEY: $key, VAL: $value\n";
         $ConnectionsIP{$key} = $i++;
         next;
    }
}

这是安全的,因为您调用keys,重置了迭代器。然后使用each进行完整的迭代。对keys的调用不会干扰对each的调用。

my $i = 0;
while (grep { $ConnectionsIP{$_} eq '0' } keys %ConnectionsIP){
    while ((my $key, my $value) = each (%ConnectionsIP)){
         print "KEY: $key, VAL: $value\n";
         $ConnectionsIP{$key} = $i++;

         if (grep { $ConnectionsIP{$_} eq '1' } keys %ConnectionsIP){
             print "I have 1!\n";
             sleep 10;
         }
         next;
    }
}

这不安全。在each遍历%ConnectionsIP的同时,您正在调用keys %ConnectionsIP重置each的迭代器。

经验法则:请勿将keysvalueseach混合使用。


有两种方法可以解决此问题。您可以使用Hash::StoredIterator来独立遍历哈希。

use Hash::StoredIterator qw{
    iterator
};

my $i = 0;
while (grep { $ConnectionsIP{$_} eq '0' } keys %ConnectionsIP) {
    # Create an iterator independent of the shared one in %ConnectionsIP
    my $connections_iter = iterator %ConnectionsIP;
    while (my($key, $value) = $connections_iter->()){
         print "KEY: $key, VAL: $value\n";
         $ConnectionsIP{$key} = $i++;

         if (grep { $ConnectionsIP{$_} eq '1' } keys %ConnectionsIP){
             print "I have 1!\n";
         }
         next;
    }
}

或者,更好的是,您可以重新编写代码,以免在循环内的循环中进行如此多的循环。您的代码将以n^3的身份运行,这意味着%ConnectionsIP中的键数增加了将被求立方的时间。 3需要27。4需要64。5需要125。

幸运的是,您的代码看起来只是测试这种行为的一些代码。