Re: whats wrong with this code?
by kcott (Archbishop) on Jan 18, 2017 at 09:01 UTC
|
G'day purnak,
Welcome to the Monastery.
From "perlsyn: Foreach Loops":
"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 with splice. So don't do that."
| [reply] [d/l] |
Re: whats wrong with this code?
by Corion (Patriarch) on Jan 18, 2017 at 08:55 UTC
|
You're iterating over an array that you are modifying at the same time. This is not a recommended approach and doesn't do what you want anyway:
foreach(@array){
shift (@array);
Most likely you want to keep on going while the array @array is not empty. Using a while loop is better for that. | [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
|
> wanted to know whats the problem with foreach?
most probably is foreach internally holding an index to iterate the array.
So it must terminate when the 6th element ( $array[5] ) is requested, because the array is already smaller then.
look at this as demonstration
use strict;
use warnings;
my @array= 1..10;
my $idx=0;
for my $elem (@array) {
print "<\$array[$idx] == $elem> @array\n";
shift @array;
$idx++
}
out:
<$array[0] == 1> 1 2 3 4 5 6 7 8 9 10
<$array[1] == 3> 2 3 4 5 6 7 8 9 10
<$array[2] == 5> 3 4 5 6 7 8 9 10
<$array[3] == 7> 4 5 6 7 8 9 10
<$array[4] == 9> 5 6 7 8 9 10
This should be clearer, HTH!
| [reply] [d/l] [select] |
Re: whats wrong with this code?
by Marshall (Canon) on Jan 18, 2017 at 10:40 UTC
|
I would code it like this (no need for the print before the loop and also swap order of statements within the loop):
#!/usr/bin/perl
use strict;
use warnings;
my @array=(1..10);
while (@array)
{
print "@array\n";
shift (@array);
}
__END__
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10
5 6 7 8 9 10
6 7 8 9 10
7 8 9 10
8 9 10
9 10
10
A for() or foreach() loop calculates some stuff before it starts looping that is not "re-calculated". That is both "good" and "bad". The while(cndx){} construct recalculates the cndx at each iteration.
Update:
This may confuse more than it helps, but an attempt...
When you iterate over foreach(@array), the default variable $_ is being set to each element of @array. The shift mucks around with this progression.
#!/usr/bin/perl
use strict;
use warnings;
my @array=(1..10);
print "@array\n";
foreach (@array)
{
#shift (@array); #see below
print "default var = $_ @array\n";
}
__END__
1 2 3 4 5 6 7 8 9 10
default var = 1 1 2 3 4 5 6 7 8 9 10
default var = 2 1 2 3 4 5 6 7 8 9 10
default var = 3 1 2 3 4 5 6 7 8 9 10
default var = 4 1 2 3 4 5 6 7 8 9 10
default var = 5 1 2 3 4 5 6 7 8 9 10
default var = 6 1 2 3 4 5 6 7 8 9 10
default var = 7 1 2 3 4 5 6 7 8 9 10
default var = 8 1 2 3 4 5 6 7 8 9 10
default var = 9 1 2 3 4 5 6 7 8 9 10
default var = 10 1 2 3 4 5 6 7 8 9 10
With the "shift turned on" (not commented out)
1 2 3 4 5 6 7 8 9 10
default var = 1 2 3 4 5 6 7 8 9 10
default var = 3 3 4 5 6 7 8 9 10
default var = 5 4 5 6 7 8 9 10
default var = 7 5 6 7 8 9 10
default var = 9 6 7 8 9 10
| [reply] [d/l] [select] |
|
Thanks for the answer. I think Im now close to understanding what happens.
| [reply] |
|
Glad to hear that this is helping. I was worried about confusing things more.
A few more comments about the difference between "while" and "foreach"..
This while loop is testing whether or not there are any elements in @array. That number of elements is the scalar value of the array. The keyword scalar is not needed because in this context it is implied. However, "scalar" can be used. The while loop does not muck with the $_ variable. But the foreach loop does.
while (scalar @array) #scalar not needed, but this is what is meant
{
print "@array\n";
shift (@array);
}
| [reply] [d/l] |
Re: whats wrong with this code?
by johngg (Canon) on Jan 18, 2017 at 12:02 UTC
|
Not answering your question but in the spirit of TIMTOWTDI, just having a play with recursion for the fun of it.
johngg@shiraz:~ > perl -Mstrict -Mwarnings -E '
my @arr = ( 1 .. 10 );
recPrint( @arr );
sub recPrint
{
@_
? do {
say join q{ }, shift, qq{@_};
&recPrint;
}
: return;
}'
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10
5 6 7 8 9 10
6 7 8 9 10
7 8 9 10
8 9 10
9 10
10
Using a while loop is the obvious and simplest way to go though.
| [reply] [d/l] [select] |
Re: whats wrong with this code?
by Discipulus (Canon) on Jan 18, 2017 at 09:35 UTC
|
As side note nor your expectation nor your output can be as you posted: you shift before printing, so first number will always be 2.
The interesting thing is that this to avoid syntax always stops after the first middle of the array:
perl -E "@ar=(1..$ARGV[0]);foreach(@ar){shift @ar;}print qq(@ar\n)" 4
3 4
perl -E "@ar=(1..$ARGV[0]);foreach(@ar){shift @ar;}print qq(@ar\n)" 10
6 7 8 9 10
perl -E "@ar=(1..$ARGV[0]);foreach(@ar){shift @ar;}print qq(@ar\n)" 20
11 12 13 14 15 16 17 18 19 20
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] |
|
| [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
Re: whats wrong with this code? (alternatives)
by LanX (Saint) on Jan 18, 2017 at 11:55 UTC
|
use strict;
use warnings;
my @array= 1..10;
do { print "@array\n" }
while defined shift @array;
@array= 1..10;
for (1..@array) {
print "@array\n";
shift @array;
}
| [reply] [d/l] |
|
>perl -Mstrict -w -M-warnings=uninitialized -E 'my @a=(1..5,undef,6..1
+0); say "@a" while defined shift @a'
2 3 4 5 6 7 8 9 10
3 4 5 6 7 8 9 10
4 5 6 7 8 9 10
5 6 7 8 9 10
6 7 8 9 10
>
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
|
| [reply] |