Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

whats wrong with this code?

by purnak (Acolyte)
on Jan 18, 2017 at 08:53 UTC ( [id://1179814]=perlquestion: print w/replies, xml ) Need Help??

purnak has asked for the wisdom of the Perl Monks concerning the following question:

Sorry if im being stupid, but i just dont understand what is wrong with this piece of code?
my @array=(1..10); print "@array\n"; foreach(@array){ shift (@array); print "@array\n"; }
I expect the output to be..
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
Instead the output stops at...
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

Replies are listed 'Best First'.
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."

    — Ken

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.

        doesn't do what you want anyway

      I know while instead of foreach can do what I want but just wanted to know whats the problem with foreach?
        > 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!

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

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
      Thanks for the answer. I think Im now close to understanding what happens.
        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); }
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.

    Cheers,

    JohnGG

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.
      Thanks for the answer. But

       so first number will always be 2

      Why is that so? Shift destroys the array for good. Isnt it?
        Sorry perhaps i've not noticed your first print "@array\n"; statement (or you have added it? ;=)

        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.
Re: whats wrong with this code? (alternatives)
by LanX (Saint) on Jan 18, 2017 at 11:55 UTC
    While I prefer Marshall's solution, TIMTOWTDI

    for completeness two other approaches:

    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; }

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      my @array= 1..10; do { print "@array\n" } while defined shift @array;

      That does not work if @array may contain undef.

      >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". ;-)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1179814]
Approved by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2024-04-19 14:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found