Какая наилучшая реализация (с точки зрения скорости и использования памяти) для итерации через массив Perl? Есть ли лучший способ? (@Array
не нужно сохранять).
foreach (@Array)
{
SubRoutine($_);
}
while($Element=shift(@Array))
{
SubRoutine($Element);
}
while(scalar(@Array) !=0)
{
$Element=shift(@Array);
SubRoutine($Element);
}
for my $i (0 .. $#Array)
{
SubRoutine($Array[$i]);
}
map { SubRoutine($_) } @Array ;
С точки зрения скорости: # 1 и # 4, но не в большинстве случаев.
Вы можете написать контрольный пример для подтверждения, но я подозреваю, что вы найдете # 1 и # 4 немного быстрее, потому что работа итерации выполняется в C вместо Perl, и не происходит ненужного копирования элементов массива. ($_
является псевдонимом элемента в # 1, но # 2 и # 3 фактически копируют скаляры из массива.)
# 5 может быть аналогичным.
В терминах использования памяти: они все одинаковые, кроме # 5.
for (@a)
имеет специальную форму, чтобы избежать сглаживания массива. Цикл выполняет итерацию по индексам массива.
С точки зрения читаемости: # 1.
С точки зрения гибкости: # 1/# 4 и # 5.
# 2 не поддерживает элементы, которые являются ложными. # 2 и # 3 являются разрушительными.
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
, будет самым быстрым, но затем отказаться от совместимости с pre-5.12.1 perl
s.
В некоторых случаях может быть уместен какой-то другой шаблон, чем они.
each
будет самым медленным. Он выполняет всю работу других, за исключением псевдонима, а также списка назначений, двух скалярных копий и двух скалярных очисток.
for
итерации по индексам массива и на 20% быстрее при итерации по индексам ссылки на массив (у меня есть доступ к $array->[$i]
в теле), при использовании each
в сочетании с while
,
IMO, реализация № 1 типична и короткая и идиоматическая для Perl превосходит остальных только для этого. Тест на три варианта может дать вам представление о скорости, по крайней мере.
1 существенно отличается от 2 и 3, так как он оставляет массив в такте, тогда как остальные два оставляют его пустым.
Я бы сказал, что №3 довольно дурацкая и, вероятно, менее эффективная, поэтому забудьте об этом.
Что оставляет вас С# 1 и # 2, и они не делают то же самое, поэтому нельзя быть "лучше", чем другой. Если массив большой, и вам не нужно его хранить, обычно область действия будет иметь дело с ним (но см. ПРИМЕЧАНИЕ), поэтому, как правило, # 1 по-прежнему является самым ясным и простым методом. Сдвиг каждого элемента не ускорит его. Даже если есть необходимость освободить массив из ссылки, я бы просто пошел:
undef @Array;
когда это сделано.
@Array = ();
не освобождает базовый массив. Даже выход за рамки этого не сделает. Если бы вы хотели освободить базовый массив, вы бы использовали undef @Array;
,
perl -MDevel::Peek -e'my @a; Dump(\@a,1); @a=qw( abc ); Dump(\@a,1); @a=(); Dump(\@a,1); undef @a; Dump(\@a,1);' 2>&1 | grep ARRAY
В одной строке для печати элемента или массива.
print $_ for (@array);
ПРИМЕЧАНИЕ: помните, что $_ внутренне ссылается на элемент @array в цикле. Любые изменения, внесенные в $_, будут отражены в @array; ех.
my @array = qw( 1 2 3 );
for (@array) {
$_ = $_ *2 ;
}
print "@array";
вывод: 2 4 6
map
и приемлемый ответ? И т. Д.)