5

我刚刚开始学习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. 为什么没有这样的线?是不是因为在 print 的迭代之后,7 4数组中剩余的元素数量等于已经完成的迭代次数,就 Perl 而言,循环完成了吗?

4

3 回答 3

8

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

如果 的任何部分LIST是一个数组,foreach如果您在循环体内添加或删除元素(例如使用splice. 所以不要那样做。

如果您$_在循环 ( print ("$x $y $_\n");) 期间打印出来,您可以看到发生了什么:

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

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

于 2012-10-17T05:16:20.000 回答
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循环中,数组@x在标量上下文中解释的,因此 while 循环将继续进行,直到其中的元素数@x为零。

于 2012-10-17T05:17:35.330 回答
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");
}
于 2012-10-17T05:50:36.957 回答