it-roy-ru.com

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

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

@x = qw(a b c);

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

foreach (@x) {
    print;
}

напечатает:

abc

Есть ли аналогичный способ получить index текущего элемента, не обновляя счетчик вручную? Нечто такое как:

foreach (@x) {
    print $index;
}

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

012
70
Nathan Fellman

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

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

В 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 list, который содержит каждое целое число от 0 до бесконечности (по крайней мере, теоретически). -> $elem, $index говорит, что мы берем два значения за раз из результата Zip. Все остальное должно выглядеть нормально для вас (если вы еще не знакомы с функцией say из 5.10).

42
Chas. Owens

perldoc perlvar, похоже, не предлагает никакой такой переменной.

23
Alan Haggai Alavi

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

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

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
5
Venkata Raju

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

4
surendra ben

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

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

когда используется для индексации

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

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

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

4
Hynek -Pichi- Vychodil

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 /

2
draegtun

Ну есть такой способ 

use List::Rubyish;

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

см. Список :: Рубиновые

1
Axeman

Я пытался, как ....

@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
surendra ben

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

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

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

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

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

0
anonymous coward