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

Hi monks, I am simply counting along an array and extracting numbers from $i and $i+1 at each position, I am getting the results I expect up until a point and wondered if it was because the counter is running off the end of the array as it only has problems when $i + 1 is used. Is there a better way of doing this? I added a test loop in as below and i get one of the error (ohh noo) messages. Thanks monks x
my $end = pop @array; for (my $i = 0; $i < @array; $i++) { if ($array[$i] =~ m/\D{1}(\D?\d+\D?\d*)\D{1}(\D?\d+\D?\d*) +\D{1}/ ) { $x1 = $2; $y1 = $1; } if (($array[$i + 1] =~ m/\D{1}(\D?\d+\D?\d*)\D{1}(\D?\d+\D +?\d*)\s*\D{1}/ ) || ($grads[$i+1] != $end)) { $x2 = $2; $y2 = $1; } else { print "ohhh noooo <P>"; } }

Replies are listed 'Best First'.
Re: counter issues
by Skeeve (Parson) on May 13, 2003 at 12:35 UTC
    for (my $i = 0; $i < @array; $i++)
    this will run from 0 to your last used index. Resulting in:
    $array[$i + 1]
    accessing an undef-ined value.
Re: counter issues
by Limbic~Region (Chancellor) on May 13, 2003 at 13:58 UTC
    Anonymous Monk,
    You could get around your problem if you re-write your code as follows:
    for (my $i = 0; $i < $#array; $i++) { if ($array[$i] =~ m/\D{1}(\D?\d+\D?\d*)\D{1}(\D?\d+\D?\d*)\D{1}/ ) + { $x1 = $2; $y1 = $1; } if (($array[$i + 1] =~ m/\D{1}(\D?\d+\D?\d*)\D{1}(\D?\d+\D?\d*)\s* +\D{1}/ ) { $x2 = $2; $y2 = $1; } }
    This is because $#array will be the index of the last element. By stopping at one less than this value, you know that $i + 1 will still be defined. This is not the best code, but I worked with what you had already shown - good job.

    Cheers - L~R

Re: counter issues
by Aristotle (Chancellor) on May 13, 2003 at 14:48 UTC
    You could use the foreach LIST form of the loop here for simplification. It will usually avoid mistakes such as the one you made, categorized as "off by one errors". Also, note that using the matches in list context here may save you from writing (and maintaining) a lot of banal code.
    for my $i (0 .. $#array - 1) { ($x1, $y1) = ($array[$i] =~ m/\D(\D?\d+\D?\d*)\D(\D?\d+\D?\d*)\D/; ($x2, $y2) = ($array[$i + 1] =~ m/\D(\D?\d+\D?\d*)\D(\D?\d+\D?\d*) +\s*\D/); }

    Makeshifts last the longest.

      One caveat with using foreach:
      What foreach actually does is first create an anonymous copy of the array you are foreach'ing over, then iterates over the copy of the list. So, if your list is rather large, foreach may result in memory usage issues.
        And for(;;) internally compiles to a while(){} continue{} construct which is pretty slow. If you have determined that the foreach loop is causing problems, you could resort to a regular while loop:
        my $i = 0; while($i++ < $#array) { ($x1, $y1) = ($array[$i] =~ m/\D(\D?\d+\D?\d*)\D(\D?\d+\D?\d*)\D/; ($x2, $y2) = ($array[$i + 1] =~ m/\D(\D?\d+\D?\d*)\D(\D?\d+\D?\d*) +\s*\D/); }
        But the foreach loop is much easier to read, so unless it was absolutely necessary I'd stick with that one.

        Makeshifts last the longest.