Perl:为什么for和foreach给我不同的结果?

时间:2016-07-29 19:35:26

标签: arrays perl

我在线观看,似乎每个人都说它们可以互换使用。但是,当我遍历我的数组时,它给了我不同的结果。

我有一个约数组。 60个字符串元素,并过滤掉另一个数组中匹配的任何内容。但是当我使用foreach时,它只看到了45个元素的数组,所以当我打印出最终结果时,它并没有过滤掉所有内容。

只有当我使用for它才能按我的意愿工作时。这背后的原因是什么?

我设法解决了这个问题,现在我只是想了解它的工作方式。谢谢!

编辑:所以我没有提供任何例子,所以这就是我所做的:

my $i = 0;
foreach my $item (@array){
    print "\n$i : $item";
    foreach my $exclude_item (@exclude){
        chomp $exclude_item;
        if ($exclude_item eq $item){
            print "\nDEBUG: Removing $item";
            splice @array, $i, 1;
        }
    }
    $i++;
}

上面没有给我一份@array的完整清单,所以当我打印出最终结果时,里面的元素应该被过滤掉。

所以我尝试了这个(按照我的意愿工作):

for (my $i=0; $i < scalar @array; $i++){
    print "\n$i : $array[$i]";
    foreach my $exclude_item (@exclude){
        chomp $exclude_item;
        if ($exclude_item eq $array[$i]){
            print "\nDEBUG: Removing $array[$i]";
            splice @array, $i, 1;
        }
    }
}

只是附加信息,@array是通过搜索多个文件夹中的子目录列表创建的。 @array可能包含重复项。

2 个答案:

答案 0 :(得分:14)

# Foreach loop                               \           
foreach my $item (@array)                     > same     \
for my $item (@array)                        /            \
                                                           > different
# Augmented while loop                       \            /
for (my $i=0; $i < scalar @array; $i++)       > same     /
foreach (my $i=0; $i < scalar @array; $i++)  /

您不得修改迭代的数组。来自perlsyn,

  

如果LIST的任何部分是数组,如果在循环体内添加或删除元素,foreach将会非常混乱,例如使用splice。所以不要这样做。

因此,

foreach (@array){
   ...
   splice @array, $i, 1;   # XXX Error
   ...
}

请注意,您可以安全地修改要迭代的数组元素。

foreach (@array){
   $_ = uc($_);  # ok
}

最后,一个更好的解决方案:

chomp(@exclude);

my %exclude = map { $_ => 1 } @exclude;

@array = grep { !$exclude{$_} } @array;

除了更简单之外,它的扩展性要好得多 [1]

  1. 在O(E + A)时间内执行,而OP在O(E * A 2 )时间内执行。

答案 1 :(得分:6)

当人们说他们被互换使用时,他们意味着foreach关键字只是for关键字的同义词。这意味着以下两行意味着完全相同:

foreach my $item (@array) {...}
for my $item (@array) {...}

为避免疑义,我会忽略foreach关键字,并仅使用下面的for

如您所见,以下两行的行为不同:

for my $item (@array) {...}
for (my $i = 0; $i < scalar @array; $i++) {...}

manual建议不要在第一行的循环体中添加或删除@array中的元素,并且不会说出结果是什么。

如果第二行的循环体在@array之前或之前删除了$i中的元素,则结果将是跳过新位置$i的元素。如果它在$i之前或之前添加了一个元素,那么结果将是第二次循环看到旧位置$i的元素。