while loops that have an index
Perl got this syntax that allow to use a while loop without having to explicitly increment an index by doing an i++
. It is made possible by the each
function.
Let's demonstrate this in a simple test that check that and array and an array ref contains the same things:
# t/01_foo_order.t
use v5.18;
use Test::More tests => 3;
my $events_arr_ref = get_events();
my @expected_events = ('foo', 'bar', 'baz');
while ( my ( $i, $event ) = each( @$events_arr_ref )) {
is @$events_arr_ref[$i],
$expected_events[$i],
"Array element [ $i is $expected_events[$i]";
}
done_testing();
sub get_events {
return [ 'foo', 'bar', 'baz' ];
}
Let's execute our test:
$ prove -v t/01_foo_order.t
1..3
ok 1 - Array element [ 0 ] value is foo
ok 2 - Array element [ 1 ] value is bar
ok 3 - Array element [ 2 ] value is baz
ok
All tests successful.
Files=1, Tests=3, 0 wallclock secs ( 0.03 usr 0.00 sys + 0.07 cusr 0.00 csys = 0.10 CPU)
Result: PASS
while ( my ( $i, $event ) = each( @$events_arr_ref )) {}
makes possible to iterate on the $events_arr_ref
array reference and for each element found, initializing $i
and $event
with the right value.
This is quite the same than a for
loop except that you don't have to increment the index and that it must be used in case you want to iterate on the whole array.
I use it quite often, can be handsome if you want to avoid $_
. Just yet another TIMTOWTDI...
Sources:
- automatically get loop index in foreach loop in perl on StackOverflow
- The Perl5 documentation for the
each
function - Original june 2019 post on dev.to
I honestly don't find the
each @array
syntax especially nice, plus I always forget what version of Perl it was introduced in. (In fact, I tend to avoideach %hash
too.) For looping through an array with an index, I find this to be pretty readable:PS: this also gives you a neat way of skipping undefined elements:
Or skipping false elements:
Of course, you can use a lexical instead of
$_
.I am not that used to the
$#array
syntax (I knew it before but totally forgot). It seems overally more readable and concise.By the way, I know that the perldoc itself recommend not to use what I presented but, dunno I keep using it because why not 🤗
This is More Neat Ways To Do It !
I guess the aim of this post was more like a way to show an exotic thing (a
while
with an index) that exist in Perl than showing something that should be done: dunno, the syntax is quite messy, but, still not totally impossible to understand in term of "natural language". The$@array
syntax seems more clean but what about beginners who should google it (search engines are bad at querying stuff like$#
or people with bad memory? Anyway, I wrote this post first to find it in search engines easily (I really use it often because I have a very bad memory) so I guess I will now be able to find the better and more concise Tobby way.I'm certainly not saying each is a bad way to do things; I've just never really liked it myself. That's mostly because I don't like its behaviour with hashes though, not arrays.
If you make changes to the hash during the loop, it can act weird. Also, the order it loops through the hash is unpredictable.
If I'm going to loop through a hash, I generally use:
Though for big hashes with a lot of keys,
each
will perform better, so is worth consideration.