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

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

Реализация 1
<code>foreach (@Array)
{
      SubRoutine($_);
}
</code>
Реализация 2
<code>while($Element=shift(@Array))
{
      SubRoutine($Element);
}
</code>
Реализация 3
<code>while(scalar(@Array) !=0)
{
      $Element=shift(@Array);
      SubRoutine($Element);
}
</code>
Реализация 4
<code>for my $i (0 .. $#Array)
{
      SubRoutine($Array[$i]);
}
</code>
Реализация 5
<code>map { SubRoutine($_) } @Array ;
</code>
 delicateLatticeworkFever07 мая 2012 г., 21:39
@ SinanÜnür Я сочувствую вашему мнению (что есть только один способ добавить два числа),н аналогия недостаточно сильна, чтобы использовать ее пренебрежительно. Очевидно, что есть несколько способов, и ОП хочет понять, что является хорошей идеей, а что нет.
 workwise30 сент. 2013 г., 18:10
Один из способов добавить два числа? Нет, если вы посмотрите на вызовы / реализации более низкого уровня .... подумайте, не стоит ли заглядывать вперед, переносить сохранение сумматоров и т.
 Sinan Ünür07 мая 2012 г., 21:21
Два из трех, которые вы разместили, заставили меня сказать "WTH ?!" разве что в качестве дополнительного окружающего контекста существуют разумные альтернативы. В любом случае этот вопрос находится на уровне "@&quo Как лучше всего добавить два числа? "В большинстве случаев есть только один выход. Тогда возникают обстоятельства, когда вам нужен другой способ. Голосование закрывается.
 Max Lybbert07 мая 2012 г., 20:50
Почему будет "лучший"? Особенно учитывая, что мы понятия не имеем, как бы вы сравнивали одно с другим (важнее ли скорость, чем использование памятmap и приемлемый ответ? так далее.
 user28908607 мая 2012 г., 23:14
Глава 24 третьего издания по программированию В Perl есть раздел, посвященный эффективности, который хорошо читается. Это касается различных типов эффективности, таких как время, программист, сопровождающий. Раздел начинается с выражения «Обратите внимание, что оптимизация по времени может иногда стоить вам пространства или эффективности программиста (на что указывают противоречивые подсказки ниже

Ответы на вопрос(6)

Решение Вопроса

№ 1 и № 4, но не намного в большинстве случаев.

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

# 5 может быть похожим.

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

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

С точки зрения читабельности: # 1.

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

# 2 не поддерживает ложные элементы. № 2 и № 3 разрушительны.

 jaypal singh17 авг. 2014 г., 21:50
Вау, ты добавил кучу информации в короткие и простые предложения.
 Thorsten Schöning14 янв. 2019 г., 12:40
Разве реализация 4 не создает промежуточный массив индексов, который может вводить большой объем используемой памяти? Если это так, похоже, не следует использовать этот подход. / Stackoverflow.com вопросы / 6440723 / ... Rt.cpan.org / Public / Bug / display.html? ID = 115863
 ikegami02 февр. 2015 г., 15:40
# 2 - это хорошо, когда вы делаете очереди (например, поиск в ширину):my @todo = $root; while (@todo) { my $node = shift; ...; push @todo, ...; ...; }

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

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

ил

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

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

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

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

Если вам нужен элемент и его индекс в теле цикла, Я бы ожидал с помощьюeach Быть самым быстрым, но потом вы отказываетесь от совместимости с пре-5.12.1perl S.

Некоторые обстоятельства могут отличаться от указанных при определенных обстоятельствах.

 ikegami08 мая 2012 г., 04:44
Я бы ожидалeach чтобы быть самым медленным. Он выполняет всю работу остальных, за исключением псевдонима, а также назначения списка, двух скалярных копий и двух скалярных очисток.
 Sinan Ünür08 мая 2012 г., 05:48
И, насколько мне известно, ты прав. Около 45% быстрее сfor перебирая индексы массива, и на 20% быстрее, когда перебираю индексы массива (у меня есть доступ$array->[$i] в теле), используяeach в сочетании сwhile.

так как он оставляет массив в такте, тогда как два других оставляют его пустым.

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

Который оставляет вас с № 1 и № 2, и они не делают одно и то же, поэтому одно не может быть «лучше», чем другое. Если массив большой и вам не нужно его хранить,вообщ сфера справится с этим но посмотри НОТ), таквообщ, # 1 - самый простой и понятный метод. Сдвиг каждого элемента не ускорит ничего. Даже если есть необходимость освободить массив от ссылки, я бы просто пошел:

undef @Array;

когда закончишь.

НОТ: Подпрограмма, содержащая область действия массива, фактически сохраняет массив и повторно использует пространство в следующий раз.Вообщ, это должно быть хорошо (см. комментарии).
 ikegami07 мая 2012 г., 22:06
Demo;perl -MDevel::Peek -e'my @a; Dump(\@a,1); @a=qw( a b c ); Dump(\@a,1); @a=(); Dump(\@a,1); undef @a; Dump(\@a,1);' 2>&1 | grep ARRAY
 delicateLatticeworkFever07 мая 2012 г., 22:11
@ ikegami: я вижу в() противundef, но если выход за пределы области не освобождает память, используемую локальным для этой области массивом, разве это не делает Perl утечкой? Что Не может будь настоящим
 ikegami07 мая 2012 г., 22:04
@Array = (); не освобождает базовый массив. Даже выход за рамки этого не сделает. Если бы вы хотели освободить базовый массив, вы бы использовалиundef @Array;.
 delicateLatticeworkFever07 мая 2012 г., 22:07
ЧТО?? Я думал, что когда-то весь смысл GC заключался в подсчете ссылок == 0, используемая память перерабатывается.
 ikegami07 мая 2012 г., 22:26
Они тоже не протекают. Подчиненный по-прежнему владеет ими и будет использовать их при следующем вызове. Оптимизировано для скорости.

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

Лучший способ решить подобные вопросы, чтобы сравнить их:

use strict;
use warnings;
use Benchmark qw(:all);

our @input_array = (0..1000);

my $a = sub {
    my @array = @{[ @input_array ]};
    my $index = 0;
    foreach my $element (@array) {
       die unless $index == $element;
       $index++;
    }
};

my $b = sub {
    my @array = @{[ @input_array ]};
    my $index = 0;
    while (defined(my $element = shift @array)) {
       die unless $index == $element;
       $index++;
    }
};

my $c = sub {
    my @array = @{[ @input_array ]};
    my $index = 0;
    while (scalar(@array) !=0) {
       my $element = shift(@array);
       die unless $index == $element;
       $index++;
    }
};

my $d = sub {
    my @array = @{[ @input_array ]};
    foreach my $index (0.. $#array) {
       my $element = $array[$index];
       die unless $index == $element;
    }
};

my $e = sub {
    my @array = @{[ @input_array ]};
    for (my $index = 0; $index < $#array; $index++) {
       my $element = $array[$index];
       die unless $index == $element;
    }
};

my $f = sub {
    my @array = @{[ @input_array ]};
    while (my ($index, $element) = each @array) {
       die unless $index == $element;
    }
};

my $count;
timethese($count, {
   '1' => $a,
   '2' => $b,
   '3' => $c,
   '4' => $d,
   '5' => $e,
   '6' => $f,
});

И запускает это на Perl 5, версия 24, Subversion 1 (v5.24.1), созданная для x86_64-linux-gnu-thread-multi

Я получил

Benchmark: running 1, 2, 3, 4, 5, 6 for at least 3 CPU seconds...
         1:  3 wallclock secs ( 3.16 usr +  0.00 sys =  3.16 CPU) @ 12560.13/s (n=39690)
         2:  3 wallclock secs ( 3.18 usr +  0.00 sys =  3.18 CPU) @ 7828.30/s (n=24894)
         3:  3 wallclock secs ( 3.23 usr +  0.00 sys =  3.23 CPU) @ 6763.47/s (n=21846)
         4:  4 wallclock secs ( 3.15 usr +  0.00 sys =  3.15 CPU) @ 9596.83/s (n=30230)
         5:  4 wallclock secs ( 3.20 usr +  0.00 sys =  3.20 CPU) @ 6826.88/s (n=21846)
         6:  3 wallclock secs ( 3.12 usr +  0.00 sys =  3.12 CPU) @ 5653.53/s (n=17639)

Так что «foreach (@Array)» примерно в два раза быстрее других. Все остальные очень похожи.

@ ikegami также отмечает, что в этих значениях, кроме скорости, есть довольно много различий.

print $ _ for (@array);

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

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

output: 2 4 6

Ваш ответ на вопрос