in reply to Re^2: Array Processing
in thread Array Processing

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

Replies are listed 'Best First'.
Re^4: Array Processing
by liverpole (Monsignor) on Oct 08, 2005 at 16:37 UTC
    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

        Whoa -- my sincere apologies!  I can only surmise that I read it too quickly and my fingers typed in the idiom that they were used to.  So I sheepishly retract what I said about your infinite loop:
        my @a = qw(1 2 3 4 5); while ((my $a, @a) = @a) { printf "\$a is now '%s', and \@a is now (%s)\n", $a, join(')(',@a) +; } # Output ... $a is now 1, and @a is now (2)(3)(4)(5) $a is now 2, and @a is now (3)(4)(5) $a is now 3, and @a is now (4)(5) $a is now 4, and @a is now (5) $a is now 5, and @a is now ()
        My initial reaction was that it's wasteful to reassign the entire array, but then I saw you had already noted this inefficiency.

        And yes, it's a reasonable observation about the possibility of an undef element, but in most cases one doesn't need to deal with arrays containing undefined values.  Then of course you'd be better off with something like:

        while (@a) { my $a = shift @a; # Use $a ... }
        Or what BUU suggests next ... :-)
      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.