Автоматически получить индекс цикла в цикле foreach в perl

Если у меня есть следующий массив в Perl:

@x = qw(a b c);

и я перебираю его с помощью foreach, тогда $_ будет ссылаться на текущий элемент в массиве:

foreach (@x) {
    print;
}

напечатает:

abc

Есть ли аналогичный способ получить индекс текущего элемента, без ручного обновления счетчика? Что-то вроде:

foreach (@x) {
    print $index;
}

где $index обновляется как $_, чтобы получить результат:

012

Ответ 1

Как и codehead, вам придется перебирать индексы массива вместо его элементов. Я предпочитаю этот вариант для цикла цикла C:

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

Ответ 2

В Perl до 5.10 вы можете сказать

#!/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";
}    

В Perl 5.10 вы используете state, чтобы объявить переменную, которая никогда не получает повторной инициализации (в отличие от тех, которые создаются с помощью my). Это позволяет сохранить переменную $index в меньшей области, но может привести к ошибкам (если вы введете цикл во второй раз, все равно будет иметь последнее значение):

#!/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";
}

В Perl 5.12 вы можете сказать

#!/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";
}

Но будьте осторожны: у вас есть ограничения на то, что вам разрешено делать с @a, итерации по нему с помощью each.

Теперь вам это не поможет, но в Perl 6 вы сможете сказать

#!/usr/bin/perl6

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

Оператор Z связывает два списка вместе (т.е. он берет один элемент из первого списка, затем один элемент из второго, затем один элемент из первого и т.д.). Второй список - это lazy список, содержащий все целые числа от 0 до бесконечности (по крайней мере теоретически). -> $elem, $index говорит, что мы берем два значения за раз от результата zip. Остальное должно выглядеть нормально для вас (если вы еще не знакомы с функцией say от 5.10).

Ответ 3

perldoc perlvar, похоже, не предлагает такую ​​переменную.

Ответ 4

Не с foreach. Если вам определенно нужна мощь элемента в массиве, используйте итератор 'for'.

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

Ответ 5

Perl версия 5.14.4

Может быть сделано с помощью цикла while (foreach не поддерживает это)

my @arr = (1111, 2222, 3333);

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

Вывод:

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

Ответ 6

Нет, вы должны сделать свой счетчик. Еще один пример:

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

при индексировании

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

И, конечно, вы можете использовать local $index; вместо my $index; и так далее.

EDIT: обновлено в соответствии с первым ysth комментарием.

Ответ 7

Да. Я проверил так много книг и других блогов... вывод заключается в том, что для счетчика циклов нет системной переменной. мы должны сделать свой счетчик. исправьте меня, если я ошибаюсь.

Ответ 8

autobox::Core предоставляет еще много удобного метода for:

use autobox::Core;

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

Альтернативно посмотрите на модуль итератора, например: Array::Iterator

use Array::Iterator;

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

Также смотрите:

/I3az/

Ответ 9

Ну так:

use List::Rubyish;

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

см. List::Rubyish

Ответ 10

Вам не нужно знать индекс в большинстве случаев, вы можете это сделать

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

В этом случае вывод будет 2, 3, 4, поскольку foreach устанавливает псевдоним для фактического элемента, а не только для копии.

Ответ 11

Я пробовал как....

@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.

короче..

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

Ответ 12

Пожалуйста примите к сведению:

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

Ответ 13

Ах, да, вы можете! (вроде, но вы не должны). each(@array) в скалярном контексте дает вам текущий индекс массива.

@a = (a..z);
for (@a){ 
  print each(@a) . "\t" . $_ . "\n"; 
}

Здесь each(@a) находится в скалярном контексте и возвращает только индекс, а не значение этого индекса. Поскольку мы находимся в цикле for, у нас уже есть значение в $ _. Этот же механизм часто используется в цикле "Пока каждый". Та же проблема.

Проблема возникает, если вы снова сделаете for(@a), индекс не вернется к 0, как вы ожидаете, он будет undef а затем 0,1,2... один отсчет. Perldoc of each() говорит, чтобы избежать этой проблемы, используйте цикл for для отслеживания индекса. https://perldoc.perl.org/functions/each.html

В принципе:

for(my $i=0; $i<=$#a; $i++){
  print "The Element at $i is $a[$i]\n";
}

Я фанат альтернативного метода:

my $index=0;
for (@a){
  print "The Element at $index is $a[$index]\n";
  $index++;
}