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

64

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

@x = qw(a b c);

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

foreach (@x) {
    print;
}

напечатает:

abc

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

foreach (@x) {
    print $index;
}

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

012
Теги:
foreach

11 ответов

98
Лучший ответ

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

for my $i (0 .. $#x) {
    print "$i: $x[$i]\n";
}
  • 13
    +1 за то, что не использовал уродливый цикл for в стиле C.
  • 3
    Это не то, что вам нужно, если последовательность индекса массива равна 2, 5, 8, 19 с пробелами в последовательности. Я считаю, что вопрос был что-то относительно индекса текущего элемента.
40

В 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).

  • 0
    Мне не нравится раздел о state , я думаю, что он будет лучше обслуживаться { my $index; ... }
  • 1
    Большой! Многому научился.
21

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

  • 15
    +1 за то, что научил человека ловить рыбу
  • 6
    -1. Это полностью противоречит духу Stackoverflow.
Показать ещё 3 комментария
7

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

for($i=0;$i<@x;++$i) {
  print "Element at index $i is ",$x[$i],"\n";
}
  • 5
    foreach и for являются взаимозаменяемыми синонимами. Некоторые вводные материалы пытаются использовать для обозначения цикла в стиле C и foreach для цикла итератора списка, но такое использование терминологии не будет всем знакомо.
  • 1
    foreach и for являются / not / взаимозаменяемыми, как показывает этот пример.
Показать ещё 4 комментария
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
4

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

4

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

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

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

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

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

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

  • 1
    0+ не является встроенным; postincrement возвращает 0, если приращенная переменная была undef.
  • 0
    Вам не нужны местные там. мой будет работать просто отлично.
Показать ещё 1 комментарий
1

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/

  • 0
    Я бы заменил ссылки на дистрибутивы ссылкой на форму: search.cpan.org/perldoc/Array::Iterator
  • 0
    @ Брэд Гилберт: изменено. Хотя лично я предпочитаю представление верхнего уровня (домашнее), представленное search.cpan.org/dist/Array-Iterator
Показать ещё 2 комментария
0

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

@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;
  • 0
    так что вы в основном предлагаете мне отслеживать индекс вручную.
0

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

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

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

  • 0
    Что произойдет, если вы замените первую строку на: my @arr = ('foo', 'bar', 'foo');
  • 0
    Он напечатал бы 1, 1, 1, поскольку строковые скаляры оцениваются в ноль при использовании в числовом контексте.
Показать ещё 1 комментарий
0

Ну так:

use List::Rubyish;

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

см. List::Rubyish

Ещё вопросы

Сообщество Overcoder
Наверх
Меню