Encontre o tamanho de uma matriz no Perl

243

Parece que me deparei com várias maneiras diferentes de encontrar o tamanho de uma matriz. Qual é a diferença entre esses três métodos?

my @arr = (2);
print scalar @arr; # First way to print array size

print $#arr; # Second way to print array size

my $arrSize = @arr;
print $arrSize; # Third way to print array size
David
fonte
13
outras maneiras: print 0+@arr, print "".@arr,print ~~@arr
mob
3
@mob, hum, pode-se evitar "".@arrcomo "@arr"algo completamente diferente.
Ikegami
39
A "segunda maneira" não é uma forma de imprimir o tamanho da matriz ...
tadmc
no contexto escalar; @arr retorna o tamanho da tabela. $ x = @ arr é um contexto escalar. $ # arr retorna o último índice da matriz. indexação começando em 0, então é a equação verdadeira $ # arr + 1 == @arr. Se você escrever algum elemento fora de ordem, por exemplo $ arr [100] = 'any', a tabela será automaticamente aumentada para o índice máximo 100 e (incluindo o índice 0) para 101 elementos.
Znik 24/1018

Respostas:

234

A primeira e a terceira maneira são as mesmas: elas avaliam uma matriz no contexto escalar. Eu consideraria essa a maneira padrão de obter o tamanho de uma matriz.

A segunda maneira, na verdade, retorna o último índice da matriz, que não é (geralmente) o mesmo que o tamanho da matriz.

Chris Jester-Young
fonte
29
O tamanho de (1,2,3) é 3 e os índices são (por padrão) 0, 1 e 2. Portanto, $ # arr será 2 neste caso, não 3.
Nate CK
5
A variável predefinida $[especifica "O índice do primeiro elemento em uma matriz e do primeiro caractere em uma substring" ( perldoc perlvar). É definido como 0 por padrão, e defini-lo como algo diferente de 0 é altamente desencorajado.
Keith Thompson
5
@Keith Thompson, $[está desanimado (e há uma década). $[está obsoleto. Usar $[emite um aviso de descontinuação, mesmo quando não é ativado os avisos. Atribuir qualquer coisa, exceto zero $[, será um erro no 5.16. Já podemos parar de mencionar $[?
ikegami
2
@ Keith Thompson, acima de 5,14, na verdade. Mas, como eu disse, foi desencorajado e reprovado por muito mais tempo do que isso, e alguém que usasse $[saberia de seus efeitos.
Ikegami
7
@ikegami: Sim, mas alguém tentando entender a diferença scalar @arre ainda$#arr deve entender os possíveis efeitos , por mais raros que sejam. $[
Keith Thompson
41

Primeiro, o segundo não é equivalente aos outros dois. $#arrayretorna o último índice da matriz, que é um a menos que o tamanho da matriz.

Os outros dois são praticamente iguais. Você está simplesmente usando dois meios diferentes para criar um contexto escalar. Tudo se resume a uma questão de legibilidade.

Pessoalmente, prefiro o seguinte:

say 0+@array;          # Represent @array as a number

Acho mais claro que

say scalar(@array);    # Represent @array as a scalar

e

my $size = @array;
say $size;

O último parece bem claro sozinho assim, mas acho que a linha extra tira a clareza quando parte de outro código. É útil para ensinar o que @arrayfaz no contexto escalar, e talvez se você quiser usar $sizemais de uma vez.

ikegami
fonte
15
Pessoalmente, prefiro a versão que usa a palavra-chave "escalar", porque é bastante explícito que está forçando um contexto escalar. my $size=@arrayparece que pode ser um erro quando o símbolo errado foi usado.
Nate CK
5
Essa é uma péssima ideia. Pessoas que usam scalarsem motivo aprendem a lição errada. Eles começam a pensar que os operadores retornam listas que podem ser coagidas em escalares. Visto dezenas de vezes.
Ikegami #
2
Por que isso "não há razão"? Você está usando scalarporque está coagindo a lista a um contexto escalar. Essa é a razão certa para usá-lo. Seu exemplo faz exatamente a mesma coisa, mas depende do que o Perl faz quando você avalia uma variável de lista em um contexto implicitamente escalar. Portanto, seu exemplo exige que o leitor conheça o comportamento implícito do Perl nesse contexto. Você está apenas adicionando mais uma camada de comportamento implícito à expressão, e o Perl já tem um comportamento implícito demais que você precisa analisar para decifrar um programa.
Nate CK
2
@Nate CK, Re "Por que isso" não há razão "? Você está usando scalarporque está coagindo a lista a um contexto escalar". Você está provando meu ponto de aprender a lição errada. Isto é completamente falso. Nenhuma lista é coagida scalar. (Se sim, scalar(@array)e scalar(@array[0..$#array])retornaria a mesma coisa.) scalar(@array)Diz @arraypara retornar um escalar, com o qual você já disse my $size=.
Ikegami
2
Acredite ou não, os desenvolvedores precisam depurar o código escrito por outros desenvolvedores. E os desenvolvedores precisam depurar o código que eles escreveram três anos atrás.
Nate CK
27

Isso obtém o tamanho forçando a matriz em um contexto escalar, no qual é avaliada como seu tamanho:

print scalar @arr;

Essa é outra maneira de forçar a matriz para um contexto escalar, pois está sendo atribuída a uma variável escalar:

my $arrSize = @arr;

Isso obtém o índice do último elemento da matriz, então, na verdade, é o tamanho menos 1 (assumindo que os índices iniciam em 0, o que é ajustável no Perl, embora isso seja geralmente uma má idéia):

print $#arr;

Este último não é realmente bom para obter o tamanho da matriz. Seria útil se você apenas deseja obter o último elemento da matriz:

my $lastElement = $arr[$#arr];

Além disso, como você pode ver aqui no Stack Overflow, essa construção não é tratada corretamente pela maioria dos marcadores de sintaxe ...

Nate CK
fonte
2
Uma nota lateral: basta usar $arr[-1]para obter o último elemento. E $arr[-2]para obter o penúltimo, e assim por diante.
tuomassalo
1
@tuomassalo: Concordo que sua sugestão é uma abordagem melhor. Em retrospecto, $#arrnão é um recurso muito útil e não é por acaso que outros idiomas não o possuem.
Nate CK
6

Para usar a segunda maneira, adicione 1:

print $#arr + 1; # Second way to print array size
jhoanna
fonte
for [0..$#array] { print $array[$_ ] } funciona muito bem se o objetivo de obter o número de elementos for iterar através da matriz. A vantagem é que você obtém o elemento e um contador que estão alinhados.
Westrock 9/02/16
5

Todos os três dão o mesmo resultado se modificarmos um pouco o segundo:

my @arr = (2, 4, 8, 10);

print "First result:\n";
print scalar @arr; 

print "\n\nSecond result:\n";
print $#arr + 1; # Shift numeration with +1 as it shows last index that starts with 0.

print "\n\nThird result:\n";
my $arrSize = @arr;
print $arrSize;
Zon
fonte
5
Isso é diferente do que já foi mencionado nesta resposta e nesta ?
devnull
5

Exemplo:

my @a = (undef, undef);
my $size = @a;

warn "Size: " . $#a;   # Size: 1. It's not the size
warn "Size: " . $size; # Size: 2
dimas
fonte
2

A seção “Tipos de variáveis ​​Perl” da documentação do perlintro contém

A variável especial $#arrayinforma o índice do último elemento de uma matriz:

print $mixed[$#mixed];       # last element, prints 1.23

Você pode ser tentado a usar $#array + 1para informar quantos itens existem em uma matriz. Não se incomode. Por acaso, o uso de @arrayonde o Perl espera encontrar um valor escalar ("no contexto escalar") fornecerá o número de elementos na matriz:

if (@animals < 5) { ... }

A documentação da perldata também cobre isso na seção "Valores escalares" .

Se você avaliar uma matriz no contexto escalar, ela retornará o comprimento da matriz. (Observe que isso não é verdade para listas, que retornam o último valor, como o operador vírgula C, nem para funções internas, que retornam o que lhes apetecer retornar.) O seguinte sempre é verdadeiro:

scalar(@whatever) == $#whatever + 1;

Alguns programadores optam por usar uma conversão explícita para não deixar dúvidas:

$element_count = scalar(@whatever);

Anteriormente, na mesma seção, documenta como obter o índice do último elemento de uma matriz.

O comprimento de uma matriz é um valor escalar. Você pode encontrar o comprimento da matriz @daysavaliando $#days, como emcsh . No entanto, esse não é o comprimento da matriz; é o subscrito do último elemento, que é um valor diferente, pois normalmente existe um 0º elemento.

Greg Bacon
fonte
2

Existem várias maneiras de imprimir o tamanho da matriz. Aqui estão os significados de todos: Vamos dizer que nossa matriz émy @arr = (3,4);

Método 1: escalar

Este é o caminho certo para obter o tamanho das matrizes.

print scalar @arr;  # prints size, here 2

Método 2: número do índice

$#arrfornece o último índice de uma matriz. portanto, se a matriz tiver tamanho 10, seu último índice será 9.

print $#arr;     # prints 1, as last index is 1
print $#arr + 1; # Add 1 to last index to get array size

Estamos adicionando 1 aqui, considerando a matriz como indexada em 0 . Mas, se não for zero, então, essa lógica falhará .

perl -le 'local $[ = 4; my @arr=(3,4); print $#arr + 1;'   # prints 6

O exemplo acima imprime 6, porque definimos seu índice inicial como 4. Agora, o índice seria 5 e 6, com os elementos 3 e 4, respectivamente.

Método 3:

Quando uma matriz é usada no contexto escalar, ela retorna o tamanho da matriz

my $size = @arr;
print $size;   # prints size, here 2

Na verdade, o método 3 e o método 1 são iguais.

Kamal Nayan
fonte
2

De perldoc perldata , que deve ser seguro citar:

O seguinte é sempre verdadeiro:

scalar(@whatever) == $#whatever + 1;

Contanto que você não adicione $ # qualquer que seja ++ e aumente misteriosamente o tamanho ou sua matriz.

Os índices da matriz começam com 0.

e

Você pode truncar uma matriz para nada atribuindo a lista nula () a ela. Os seguintes são equivalentes:

    @whatever = ();
    $#whatever = -1;

O que me leva ao que eu estava procurando e como detectar a matriz está vazia. Eu encontrei se $ # empty == -1;

jwal
fonte
1

Que int(@array)tal ameaçar o argumento como escalar.

Reflexivo
fonte
0

Para encontrar o tamanho de uma matriz, use a scalarpalavra-chave:

print scalar @array;

Para descobrir o último índice de uma matriz, existe $#(variável padrão Perl). Fornece o último índice de uma matriz. Quando uma matriz começa em 0, obtemos o tamanho da matriz adicionando uma a $#:

print "$#array+1";

Exemplo:

my @a = qw(1 3 5);
print scalar @a, "\n";
print $#a+1, "\n";

Resultado:

3

3
Sandeep_black
fonte