Tutorial :automatically get loop index in foreach loop in perl



Question:

If I have the following array in Perl:

@x = qw(a b c);  

and I iterate over it with foreach, then $_ will refer to the current element in the array:

foreach (@x) {      print;  }  

will print:

abc  

Is there a similar way to get the index of the current element, without manually updating a counter? Something such as:

foreach (@x) {      print $index;  }  

where $index is updated like $_ to yield the output:

012  


Solution:1

Like codehead said, you'd have to iterate over the array indices instead of its elements. I prefer this variant over the C-style for loop:

for my $i (0 .. $#x) {      print "$i: $x[$i]\n";  }  


Solution:2

In Perl prior to 5.10, you can say

#!/usr/bin/perl    use strict;  use warnings;    my @a = qw/a b c d e/;    my $index;  for my $elem (@a) {      print "At index ", $index++, ", I saw $elem\n";  }    #or    for my $index (0 .. $#a) {      print "At index $index I saw $a[$elem]\n";  }      

In Perl 5.10, you use state to declare a variable that never gets reinitialized (unlike ones create with my). This lets you keep the $index variable in a smaller scope, but can lead to bugs (if you enter the loop a second time it will still have the last value):

#!/usr/bin/perl    use 5.010;  use strict;  use warnings;    my @a = qw/a b c d e/;    for my $elem (@a) {      state $index;      say "At index ", $index++, ", I saw $elem";  }  

In Perl 5.12 you can say

#!/usr/bin/perl    use 5.012; #this enables strict  use warnings;    my @a = qw/a b c d e/;    while (my ($index, $elem) = each @a) {      say "At index $index I saw $elem";  }  

But be warned: you there are restrictions to what you are allowed to do with @a while iterating over it with each.

It won't help you now, but in Perl 6 you will be able to say

#!/usr/bin/perl6    my @a = <a b c d e>;  for @a Z 0 .. Inf -> $elem, $index {      say "at index $index, I saw $elem"  }  

The Z operator zips the two lists together (i.e. it takes one element from the first list, then one element from the second, then one element from the first, and so on). The second list is a lazy list that contains every integer from 0 to infinity (at least theoretically). The -> $elem, $index says that we are taking two values at a time from the result of the zip. The rest should look normal to you (unless you are not familiar with the say function from 5.10 yet).


Solution:3

perldoc perlvar does not seem to suggest any such variable.


Solution:4

Not with foreach. If you definitely need the element cardinality in the array use a 'for' iterator.

for($i=0;$i<@x;++$i) {    print "Element at index $i is ",$x[$i],"\n";  }  


Solution:5

Perl version 5.14.4

Can be done with while loop (foreach doesn't support this)

my @arr = (1111, 2222, 3333);    while (my ($index, $element) = each(@arr))  {     # You may need to "use feature 'say';"     say "Index: $index, Element: $element";  }  

Output:

Index: 0, Element: 1111  Index: 1, Element: 2222  Index: 2, Element: 3333  


Solution:6

No, you must make your own counter. Yet another example:

my $index;  foreach (@x) {      print $index++;  }  

when used for indexing

my $index;  foreach (@x) {      print $x[$index]+$y[$index];      $index++;  }  

And of course you can use local $index; instead my $index; and so and so.

EDIT: Updated according to first ysth's comment.


Solution:7

Yes. I have checked so many books and other blogs... conclusion is, there is no system variable for the loop counter. we have to make our own counter. correct me if i m wrong.


Solution:8

autobox::Core provides among many more things a handy for method:

use autobox::Core;    ['a'..'z']->for( sub{      my ($index, $value) = @_;      say "$index => $value";  });  

Alternatively have a look at an iterator module, for eg: Array::Iterator

use Array::Iterator;    my $iter = Array::Iterator->new( ['a'..'z'] );  while ($iter->hasNext) {      $iter->getNext;      say $iter->currentIndex . ' => ' . $iter->current;  }  

Also see:

/I3az/


Solution:9

Well there is this way:

use List::Rubyish;    $list = List::Rubyish->new( [ qw<a b c> ] );  $list->each_index( sub { say "\$_=$_" } );  

see List::Rubyish


Solution:10

You shouldn't need to know the index in most circumstances, you can do this

my @arr = (1, 2, 3);  foreach (@arr) {      $_++;  }  print join(", ", @arr);  

In this case, the output would be 2, 3, 4 as foreach sets an alias to the actual element, not just a copy.


Solution:11

I have tried like....

@array = qw /tomato banana papaya potato/;                  # example array  my $count;                                                  # local variable initial value will be 0  print "\nBefore For loop value of counter is $count";       # just printing value before entering in   loop    for (@array) { print "\n",$count++," $_" ; }                # string and variable seperated by comma to                                                               # execute the value and print  undef $count;                                               # undefining so that later parts again it will                                                              # be reset to 0    print "\nAfter for loop value of counter is $count";        # checking the counter value after for loop.  

in short..

@array = qw /a b c d/;  my $count;  for (@array) { print "\n",$count++," $_"; }  undef $count;  


Solution:12

Please consider:

print "Element at index $_ is $x[$_]\n" for keys @x;  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »