Perl中'foreach'的行为

时间:2012-10-17 05:11:03

标签: perl foreach

我刚刚开始学习Perl并发现自己因以下代码块的结果而受阻:

@x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
foreach (@x) {
    $x = pop (@x) ;
    $y = shift (@x);
    print ("$x $y \n");
}

输出结果为:

10 1
9 2
8 3
7 4

我原本期待另一条线:6 5。为什么没有这样的线?是因为在打印7 4的迭代之后,数组中剩余的元素数量等于已经完成的迭代次数,因此就Perl而言,循环完成了吗?

3 个答案:

答案 0 :(得分:8)

您可能不应在迭代期间修改列表。来自perldoc perlsyn

  

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

如果您在循环($_)期间打印print ("$x $y $_\n");,则可以看到正在发生的事情:

10 1 1
9 2 3
8 3 5
7 4 7

在这种情况下,Perl只是维护一个索引,它通过数组递增。由于您从头开始删除元素,因此索引在第四次迭代结束时从修改后的数组的末尾开始,因此foreach循环终止。

答案 1 :(得分:7)

这很好地说明了当您更改要迭代的数组时会发生什么。

尝试:

use strict: #Always!
use warnings; #Always!

my @x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
my $n=$#x;
foreach my $i(0..$n) {
    my $x = pop (@x) ;
    my $y = shift (@x);
    print "$x $y\n" if defined $x and defined $y;
}

或者,更好的是:

use strict;
use warnings;

my @x=1..10; #same thing, just written more idiomatically

while(@x)
{
  my $x=pop @x; #no parentheses needed
  my $y=shift @x;
  print "$x $y\n";
}

请注意,在上面的while循环中,数组@xinterpreted in scalar context,因此while循环将继续,直到@x中的元素数为零。< / p>

答案 2 :(得分:3)

不允许修改使用foreach循环迭代的数组。

无论如何,您不想迭代数组元素。 foreach (@x)显然是错误的。这循环10次,但你只想循环5次。

由于在循环时从数组中删除元素,因此只需循环直到数组为空。要在循环的每次传递中检查条件,可以使用while循环。

my @x = 1..10;
while (@x) {
    my $x = pop(@x) ;
    my $y = shift(@x);
    print("$x $y\n");
}

如果你想使用foreach循环,它将如下所示:

my @x = 1..10;
for (1..@x/2) {
    my $x = $x[-$_];
    my $y = $x[$_-1];
    print("$x $y\n");
}