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

What is the best way to count iterations in a foreach loop? Usually, if I need to count iterations, I'll just increment a variable each time through - something like
$i = 0; foreach (@array) { # do stuff $i++; }
Is there a better way to do this? Maybe through one of Perl's special variables? I thought about searching for the array index containing the current value (like, "what is the index of @array that contains $_"). Also, I'm not necessarily looking for a solution to give me a total end count of iterations, but more for telling me how many iterations I have gone through so I can say things like "print this line every 3rd time through the loop"

Replies are listed 'Best First'.
Re: Of foreach loops and counting
by eak (Monk) on Aug 09, 2000 at 19:42 UTC
    The easiest way I know of is to do something like.
    foreach (0..$#array){ # do stuff, $_ holds iteration num. }


    --eric

      Or if you really want to use one of Perl's special variables, try this:

      for ($[..$#array) { ## Foo }
      since "0" is not necessarily the first element of the array. Of course, nobody should ever, ever change the $[ variable except as part of an obfuscated perl program. :)

      Ok, and then I would just get my array values with $array[$_] instead of having the value be in $_. Sounds good to me. Thanks.
(jeffa) Re: Of foreach loops and counting
by jeffa (Bishop) on Aug 09, 2000 at 19:47 UTC
    Hmm, if you need to keep track of iteration in a loop, then you should use for instead of foreach.
    for (my $i=0; $i < $#array; $i++) { #print every third line print "$array[$i]\n" if (($i % 3)==0); #or even more consise print "$array[$i]\n" unless ($i%3); }
    I know that for is a synonym for foreach, but I simply prefer to use a for construct if I am going to need the current iteration. Guess it's the C inside me. Oh, thanks to KM - I'll be more idiomatic next time. ;)

    /me seeks Priest to exorcise evil C demons.

      I just wanted to comment that this is a very C like way of doing this, and is more idiomatically written as (or something similar as far as the loop construct):

      for (0..$#array) { print $array[$_]; }

      Cheers,
      KM

      for is a synonym of foreach. you make the decision on which one to use based on readabilty, since both behave exactly the same.
      --eric
Re: Of foreach loops and counting
by ferrency (Deacon) on Aug 09, 2000 at 20:18 UTC
    For testing "every third iteration," I do this sometimes:

    my $n = 0; foreach (@array) { next if I_dont_care_about($_); do_something_with ($_); print "." if !($n++ % 3); } print "\n";
    If you aren't necessarily processing every item in the list, but only want to count the number of elements you process, then using a temporary variable as you were doing is a useful alternative to looping over the array indices. It also works when you're doing things like looping over hash keys, where you can't count on having a numeric index implicitly; or processing lines of a file with a while (<>) loop.

    Update: KM, that is definitely true, and a more efficient and succinct way to count lines when you're interested in the total line count. The method I presented is still useful when you want to count the number of lines you processed, not the total line count so far.

    Alan

      or processing lines of a file with a while (<>) loop.

      In that case, you can use $. (perldoc perlvar) to know what line you are in. For example:

      #!/usr/bin/perl while (<DATA>) { print $. . ": $_"; } __DATA__ a b c d e f g h i # Would display when run... $ ./test.pl 1: a 2: b 3: c 4: d 5: e 6: f 7: g 8: h 9: i

      Cheers,
      KM