Reputation: 7917
I have just begun to learn Perl and found myself stymied by the result of the following block of code:
@x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
foreach (@x) {
$x = pop (@x) ;
$y = shift (@x);
print ("$x $y \n");
}
The output is:
10 1
9 2
8 3
7 4
I had expected another line: 6 5
. Why is there not such a line? Is it because after the iteration that prints 7 4
, the number of elements left in the array is equal to the number of iterations already completed, and so as far as Perl is concerned, the loop is done?
Upvotes: 5
Views: 1398
Reputation: 385645
You're not allowed to modify the array over which you are iterating using a foreach loop.
You don't want to iterate over the array elements anyway. foreach (@x)
is clearly wrong. That loops 10 times, but you only want to loop 5 times.
Since you remove elements from the array as you loop, you simply want to loop until the array is empty. To check a condition at every pass of the loop, one uses a while loop.
my @x = 1..10;
while (@x) {
my $x = pop(@x) ;
my $y = shift(@x);
print("$x $y\n");
}
If you wanted to use a foreach loop, it would look like this:
my @x = 1..10;
for (1..@x/2) {
my $x = $x[-$_];
my $y = $x[$_-1];
print("$x $y\n");
}
Upvotes: 3
Reputation:
This is a good illustration of what happens when you change the array over which you're iterating.
Try:
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;
}
Or, better yet:
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";
}
Note in the while
loop above, the array @x
is being interpreted in scalar context, hence the while loop will continue until the number of elements in @x
is zero.
Upvotes: 7
Reputation: 179392
You probably shouldn't modify the list during iteration. From perldoc perlsyn
:
If any part of
LIST
is an array,foreach
will get very confused if you add or remove elements within the loop body, for example withsplice
. So don't do that.
If you print out $_
during the loop (print ("$x $y $_\n");
), you can see what's going on:
10 1 1
9 2 3
8 3 5
7 4 7
In this case Perl is just maintaining an index that it increments through the array. Since you delete the elements from the start, the index falls off the end of the modified array at the end of the fourth iteration, and so the foreach
loop terminates.
Upvotes: 8