in reply to Re: Array Processing
in thread Array Processing

while (my $a = shift @a) {
This won't work if the array contains anything that is false in boolean context, like 0, '', or undef. You really need to explicitly check the array's length somehow.

If you're really intent on squeezing the assignment into the while loop, try:

while ( (my $a, @a) = @a ) {
This works because when evaluated in scalar context, the list assignment ( (list) = something ) returns the number of items in the right-hand side list. This little obscurity of syntax is probably one of the toughest to come to grips with, but it can be quite elegant at times.

In this case, I wouldn't actually use it since it reassigns most of @a to itself every time and is very inefficient in that respect.

blokhead

Replies are listed 'Best First'.
Re^3: Array Processing
by japhy (Canon) on Oct 08, 2005 at 15:36 UTC
    Or use the comma operator: while (@a and my $a = shift @a, 1) { ... }

    (Updated code is in bold)


    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      In reply to blokhead, you're absolutely right about the potential early termination.  And of course, it becomes essential when reading in a file, which could contain blank lines, that instead of:
      while ($line = <$fh>) { # ... }
      you do something like:
      while (defined($line = <$fh>)) { # ... }
      But then, when I looked more carefully at the idiom you suggested, there's a subtle bug in:  while ( (my $a, @a) = @a ) {".  I realized it doesn't, in fact, reasign most of @a to iteslf every time, because you're declaring my @a (along with my $a), so it's a different @a that you're doing the assignment to!  Also, when you run it, you get an infinite loop:
      my @a = qw( 1 2 3 4 5 ); while (my ($a, @a) = shift @a) { printf "Next value = $a\n"; printf "Size of \@a = %d\n", 0 + @a; } # When run ... infinite loop! # (Note that "Size of @a" shows the temporary @a, not the original) Next value = 1 Size of @a = 0 Next value = 2 Size of @a = 0 Next value = 3 Size of @a = 0 Next value = 4 Size of @a = 0 Next value = 5 Size of @a = 0 Next value = Size of @a = 0 Next value = Size of @a = 0 Next value =
      And japhy, you've got an interesting idiom too, but it also doesn't do quite what you want, because the ",1" makes the expression eternally true, so you also get an infinite loop even after @a is exhausted.  So for now, I'll stick with the "while (defined($a = shift @a))" syntax.
        But then, when I looked more carefully at the idiom you suggested, there's a subtle bug in: while ( (my $a, @a) = @a ) {". I realized it doesn't, in fact, reasign most of @a to iteslf every time, because you're declaring my @a (along with my $a), so it's a different @a that you're doing the assignment to! Also, when you run it, you get an infinite loop:
        You are talking about the code I wrote, but the code you actually tested is very different. There is a big difference between
        (my $a, @a) = @a
        and
        my ($a, @a) = @a
        In the first case, only $a is redeclared with my. The @a variable is the same one on both sides. In the second case, both $a and @a are redeclared with my. Notice that in my reply, I used the first one. There is no infinite loop, and it really does work like I described.
        So for now, I'll stick with the "while (defined($a = shift @a))" syntax.
        Again, this will fail if there is an undef in the array. You can't get undef from <$fh> unless it's the end of the file, so it is safe to test the result of <$fh> for undef. But it is perfectly reasonable to have undef as a value in an array (and not be at the end of the array).

        blokhead

        How about:
        for( my $a; $a = shift @a; @a ) { }
        Sorry about my code being untested and erroneous. I've added a slight modification that checks the size of the array.

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

        And of course, it becomes essential when reading in a file, which could contain blank lines

        Actually, no, Perl DWIMs this.

        $ perl -MO=Deparse,-x7 -e'while($line=<$fh>){}'
        while (defined($line = <$fh>)) {
            ();
        }
        -e syntax OK

        But defined doesn’t help you in this case anyway, since undef is a legal value for an array element.

        Makeshifts last the longest.