Skip to content

each @array in Perl 5.12

June 6, 2010
tags:

Don’t recall seeing anyone blog about it and in fact the documentation is pretty sparse but from Perl 5.12 each can now iterate over an array like so:

use 5.012;
use warnings;

my @array = 'a' .. 'h';

while (my ($i, $val) = each @array) {
    say "$i => $val";
}

each on an array returns two values… the index and the value of the current iteration. Thus we get this output from above code:

  0 => a
  1 => b
  2 => c
  3 => d
  4 => e
  5 => f
  6 => g
  7 => h

Anyway to save me thinking up a blog post please excuse me while I just regurgitate my Stackoverflow answer I gave earlier today about using each with an array:

==start==
Starting with Perl 5.12, each is now more flexible by also working on arrays:

use 5.012;
use warnings;

my @tokens = 'a' .. 'z';

while (my ($i, $val) = each @tokens) {
    if ($val =~ m/[aeiou]/) {
        ($i, $val) = each @tokens;   # get next token after a vowel
        print $val;
    }
}

# => bfjpv

One caveat with each, remember the iterator is global and is not reset if you break out of a loop.

For eg:

while (my ($i, $val) = each @tokens) {
    print $val;
    last if $i == 12;
}

# => abcdefghijklm

my ($i, $val) = each @tokens;
say "Now at => $val ($i)";         # Now at => n (13)

So use keys or values to manually reset the iterator:

keys @tokens;                      # resets iterator
($i, $val) = each @tokens;
say "Now at => $val ($i)";         # Now at => a (0)

==end==

I’ve just come back from a nice weeks break… so I’m still a lazy git in holiday mode here 🙂

/I3az/

Advertisement
7 Comments leave one →
  1. poisonbit permalink
    June 6, 2010 6:24 pm

    Is there any reason to take a loop iterator out of the loop by default ?

    I don’t understand very well this change, I think that makes more sense to “add code” those who want a loop iterator outside the loop, better than to make “add code” for those who reuse semantically the same iterator in loops.

    • June 7, 2010 11:27 am

      Hi poisonbit,

      If you referring to my last two bits of code then I’m only using this as an example for the “caveat”.

      /I3az/

  2. Paul Evans permalink
    June 7, 2010 10:58 am

    Great

    So now 5.12 has further extended the awkward action-at-a-distance misfit of ‘each’ to operate on more containers than it used to on 5.10. I can see this being abused far more often, creating lots more bugs where the globalness of it accidentally leaks out, than I can see cases for it being useful.

    foreach my $idx ( 0 .. $#arr ) { my $elem = $arr[$idx] } is already neat enough. If you actually wanted to preserve the index from one loop to the next; just remove that ‘my’ start using a C-style for() loop.

    each is useful on hashes because you can’t just do that with $key; there is no obvious $key++ operation to walk to the “next” key.

    • June 7, 2010 11:41 am

      Hi Paul,

      Actually I think its quite a useful addition and I much prefer its succinctness over the alternatives. However its good to be wary and I for one would do my best avoid any self abuse it may cause using it 🙂

      BTW… using an iterator is my preferred solution. For eg. Array::Iterator mentioned in another answer in that stackoverflow question is something I would recommend.

      chars Barry

  3. Ether permalink
    July 12, 2010 4:39 pm

    keys() on an array? Really? How interesting.

Trackbacks

  1. each to their own (autobox) « transfixed but not dead!

Leave a Reply to draegtun Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: