Лучший способ итерации через массив Perl

Какая наилучшая реализация (с точки зрения скорости и использования памяти) для итерации через массив Perl? Есть ли лучший способ? (@Array не нужно сохранять).

Реализация 1

foreach (@Array)
{
      SubRoutine($_);
}

Реализация 2

while($Element=shift(@Array))
{
      SubRoutine($Element);
}

Реализация 3

while(scalar(@Array) !=0)
{
      $Element=shift(@Array);
      SubRoutine($Element);
}

Реализация 4

for my $i (0 .. $#Array)
{
      SubRoutine($Array[$i]);
}

Реализация 5

map { SubRoutine($_) } @Array ;

Ответ 1

  • С точки зрения скорости: # 1 и # 4, но не в большинстве случаев.

    Вы можете написать контрольный пример для подтверждения, но я подозреваю, что вы найдете # 1 и # 4 немного быстрее, потому что работа итерации выполняется в C вместо Perl, и не происходит ненужного копирования элементов массива. ($_ является псевдонимом элемента в # 1, но # 2 и # 3 фактически копируют скаляры из массива.)

    # 5 может быть аналогичным.

  • В терминах использования памяти: они все одинаковые, кроме # 5.

    for (@a) имеет специальную форму, чтобы избежать сглаживания массива. Цикл выполняет итерацию по индексам массива.

  • С точки зрения читаемости: # 1.

  • С точки зрения гибкости: # 1/# 4 и # 5.

    # 2 не поддерживает элементы, которые являются ложными. # 2 и # 3 являются разрушительными.

Ответ 2

Если вам нужны только элементы @Array, используйте:

for my $el (@Array) {
# ...
}

или

Если значения имеют значение, используйте:

for my $i (0 .. $#Array) {
# ...
}

Или, начиная с perl 5.12.1, вы можете использовать:

while (my ($i, $el) = each @Array) {
# ...
}

Если вам нужен как элемент, так и его индекс в теле цикла, я бы ожидал, что, используя each , будет самым быстрым, но затем отказаться от совместимости с pre-5.12.1 perl s.

В некоторых случаях может быть уместен какой-то другой шаблон, чем они.

Ответ 3

IMO, реализация № 1 типична и короткая и идиоматическая для Perl превосходит остальных только для этого. Тест на три варианта может дать вам представление о скорости, по крайней мере.

Ответ 4

1 существенно отличается от 2 и 3, так как он оставляет массив в такте, тогда как остальные два оставляют его пустым.

Я бы сказал, что №3 довольно дурацкая и, вероятно, менее эффективная, поэтому забудьте об этом.

Что оставляет вас С# 1 и # 2, и они не делают то же самое, поэтому нельзя быть "лучше", чем другой. Если массив большой, и вам не нужно его хранить, обычно область действия будет иметь дело с ним (но см. ПРИМЕЧАНИЕ), поэтому, как правило, # 1 по-прежнему является самым ясным и простым методом. Сдвиг каждого элемента не ускорит его. Даже если есть необходимость освободить массив из ссылки, я бы просто пошел:

undef @Array;

когда это сделано.

  • ПРИМЕЧАНИЕ. Подпрограмма, содержащая область массива, фактически сохраняет массив и повторно использует пробел в следующий раз. Как правило, это должно быть хорошо (см. Комментарии).

Ответ 5

В одной строке для печати элемента или массива.

print $_ for (@array);

ПРИМЕЧАНИЕ: помните, что $_ внутренне ссылается на элемент @array в цикле. Любые изменения, внесенные в $_, будут отражены в @array; ех.

my @array = qw( 1 2 3 );
for (@array) {
        $_ = $_ *2 ;
}
print "@array";

вывод: 2 4 6