Quote:
Originally Posted by indiancosmonaut
Thanks you for looking into it Telemachos,
First of all, I understood the point that you made about foreach being an internal iterate...I read more on it. But what I don't understand is that the array is still showing 5 items left in the array so why doesn't foreach try to read them? (I'm may be asking the same question in a different way!) If you believe I shouldn't be wasting my time on this then please let me know because I don't want to beat around the bush for no good reason
Another interesting this is that it only prints n/2 (where n is even) and n/2+1 (where n is odd)!!
|
Getting half-way is what you should expect since you are iterating over the array in
double-time: once via the built-in
foreach and once via
shift. By the time you get half-way, you've run out of all your elements.
This should make clearer what is happening. Alter the
foreach loop in your script so that it shows the state of the @_ array both
before and
after the shift, and so that it shows what's in the variable $k and the variable $_. The
foreach mechanism is putting an item into $_ and you are putting a second item into $k. (Actually, the first time through the two are identical, but after that you've tampered with the array, so they change.)
Here's the changed code:
Code:
foreach (@_) {
print "Interation: $i\n";
print "--------------\n";
$i+=1;
print "Before shift - @_\n";
$k = shift(@_);
print "After shift - @_\n";
print "\$k is $k and \$_ is $_\n\n";
$k = undef;
}
And its output:
Code:
Printing all the elements of the array : 100 200 300 400 500 600 700 800
Interation: 0
--------------
Before shift - 100 200 300 400 500 600 700 800
After shift - 200 300 400 500 600 700 800
$k is 100 and $_ is 100
Interation: 1
--------------
Before shift - 200 300 400 500 600 700 800
After shift - 300 400 500 600 700 800
$k is 200 and $_ is 300
Interation: 2
--------------
Before shift - 300 400 500 600 700 800
After shift - 400 500 600 700 800
$k is 300 and $_ is 500
Interation: 3
--------------
Before shift - 400 500 600 700 800
After shift - 500 600 700 800
$k is 400 and $_ is 700
Look carefully at the output. The
foreach loop iterates over an array
by keeping track of its position in a 0-indexed array. You seem to think that the
foreach loop should track the elements in the original array, but keeps track simply of where it is in sequence 0, 1, 2, 3, etc. Since you are shrinking the actual array as you go, you finish sooner than you expect. If you print out what's in $_, you can see where the
foreach loop is during each iteration.
- In the first loop, $_ is whatever is at index 0 - namely 100. Then you remove an element.
- In the second loop, $_ is whatever is at index 1, but index 1 is now 300. It's crucial that you see how I know this. Look at the printout for that iteration before the shift. The items are (200, 300, 400, 500, 600, 700, 800). Count up, starting from 0, and '300' is at index 1. Do that for each iteration to see what the foreach loop is doing. The foreach loop skipped 200 entirely since it was moved to index position 0 and the loop has already done index 0. You also removed another element from the array.
- In the third loop, $_ is whatever is at index 2, but index 2 is now 500. The loop skipped 400. Again, you remove an element from the array. It's shrinking.
- In the fourth loop, $_ is whatever is at index 3, but index 3 is now 700. You remove another element from the array.
- The next loop through, $_ should be whatever is at index 4, but the array is (500, 600, 700, 800) so there is nothing at index 4 (the fifth element in a 0-indexed array), so we're done.
See also
this post from another board for a variation on the same problem. (The OP there starts with a
while loop not a
foreach, but he also messes with the array while iterating over it.)