Qual é a melhor implementação (em termos de velocidade e uso de memória) para iterar por meio de um array Perl? Existe alguma maneira melhor? ( @Array
não precisa ser retido).
Implementação 1
foreach (@Array)
{
SubRoutine($_);
}
Implementação 2
while($Element=shift(@Array))
{
SubRoutine($Element);
}
Implementação 3
while(scalar(@Array) !=0)
{
$Element=shift(@Array);
SubRoutine($Element);
}
Implementação 4
for my $i (0 .. $#Array)
{
SubRoutine($Array[$i]);
}
Implementação 5
map { SubRoutine($_) } @Array ;
map
uma resposta aceitável? Etc.)Respostas:
Em termos de velocidade: # 1 e # 4, mas não muito na maioria dos casos.
Você poderia escrever um benchmark para confirmar, mas eu suspeito que você descobrirá que os itens 1 e 4 são um pouco mais rápidos porque o trabalho de iteração é feito em C em vez de Perl, e nenhuma cópia desnecessária dos elementos do array ocorre. (
$_
tem um alias para o elemento em # 1, mas # 2 e # 3 na verdade copiam os escalares da matriz.)# 5 pode ser semelhante.
Em termos de uso de memória: Eles são todos iguais, exceto o # 5.
for (@a)
é especial para evitar o achatamento da matriz. O loop itera sobre os índices da matriz.Em termos de legibilidade: # 1.
Em termos de flexibilidade: # 1 / # 4 e # 5.
# 2 não suporta elementos falsos. # 2 e # 3 são destrutivos.
fonte
my @todo = $root; while (@todo) { my $node = shift; ...; push @todo, ...; ...; }
Se você se preocupa apenas com os elementos de
@Array
, use:ou
Se os índices importam, use:
Ou, a partir de
perl
5.12.1, você pode usar:Se você precisar do elemento e de seu índice no corpo do loop,
eu esperariausandoeach
para ser o mais rápido, mas entãovocê estará desistindo da compatibilidade com o pré-5.12.1perl
s.Algum padrão diferente desses pode ser apropriado em certas circunstâncias.
fonte
each
que fosse o mais lento. Ele faz todo o trabalho dos outros menos um alias, mais uma atribuição de lista, duas cópias escalares e duas limpezas escalares.for
iteração sobre os índices de um array e 20% mais rápido com a iteração sobre os índices de uma referência de array (eu acesso$array->[$i]
no corpo), em vez de usareach
em conjunto comwhile
.IMO, a implementação # 1 é típica e ser curta e idiomática para Perl supera as outras apenas por isso. Um benchmark das três opções pode oferecer a você uma percepção da velocidade, pelo menos.
fonte
1 é substancialmente diferente de 2 e 3, pois deixa o array intacto, enquanto os outros dois o deixam vazio.
Eu diria que o nº 3 é bem maluco e provavelmente menos eficiente, então esqueça isso.
O que deixa você com o nº 1 e o nº 2, e eles não fazem a mesma coisa, então um não pode ser "melhor" que o outro. Se o array for grande e você não precisar mantê-lo, geralmente o escopo tratará dele ( mas veja a NOTA ), então geralmente , # 1 ainda é o método mais claro e simples. Desligar cada elemento não acelera nada. Mesmo se houver necessidade de liberar a matriz da referência, eu simplesmente diria:
quando terminar.
fonte
@Array = ();
não libera a matriz subjacente. Nem mesmo sair do escopo faria isso. Se você quisesse liberar o array subjacente, você deveria usarundef @Array;
.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
()
vsundef
, mas se sair do escopo não libera a memória usada por um array local para esse escopo, isso não torna o perl um desastre de vazamento? Isso não pode ser verdade.Em uma única linha para imprimir o elemento ou array.
imprimir $ _ para (@array);
NOTA: lembre-se de que $ _ se refere internamente ao elemento de @array no loop. Quaisquer alterações feitas em $ _ refletirão em @array; ex.
saída: 2 4 6
fonte
A melhor maneira de decidir questões como esta para compará-las:
E executando isso em perl 5, versão 24, subversão 1 (v5.24.1) construído para x86_64-linux-gnu-thread-multi
Eu recebo:
Portanto, o 'foreach (@Array)' é cerca de duas vezes mais rápido que os outros. Todos os outros são muito semelhantes.
@ikegami também aponta que existem algumas diferenças nessas implementações além da velocidade.
fonte
$index < $#array
deveria ser$index <= $#array
porque$#array
não é o comprimento da matriz, mas o último índice dela.