Encontrar el tamaño de una matriz en Perl

243

Parece que he encontrado varias formas diferentes de encontrar el tamaño de una matriz. ¿Cuál es la diferencia entre estos tres 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
fuente
13
otras maneras: print 0+@arr, print "".@arr,print ~~@arr
mafia
3
@mob, hum, uno podría evitar, al "".@arrigual "@arr"que algo muy diferente.
ikegami
39
La "segunda vía" no es una manera de imprimir el tamaño de la matriz ...
tadmc
en contexto escalar; @arr devuelve el tamaño de la tabla. $ x = @ arr es contexto escalar. $ # arr devuelve el último índice de la matriz. indexación a partir de 0, entonces es verdadera ecuación $ # arr + 1 == @arr. Si escribe algún elemento fuera de orden, por ejemplo $ arr [100] = 'any', la tabla se incrementa automáticamente al índice máximo 100 y (incluido el índice 0) a 101 elementos.
Znik

Respuestas:

234

La primera y la tercera forma son las mismas: evalúan una matriz en contexto escalar. Consideraría que esta es la forma estándar de obtener el tamaño de una matriz.

La segunda forma en realidad devuelve el último índice de la matriz, que no es (generalmente) el mismo que el tamaño de la matriz.

Chris Jester-Young
fuente
29
El tamaño de (1,2,3) es 3, y los índices son (por defecto) 0, 1 y 2. Entonces, $ # arr será 2 en este caso, no 3.
Nate CK
55
La variable predefinida $[especifica "El índice del primer elemento en una matriz y del primer carácter en una subcadena" ( perldoc perlvar). Se establece en 0 de forma predeterminada, y se desaconseja configurarlo en algo que no sea 0.
Keith Thompson el
55
@Keith Thompson, $[está desanimado (y lo ha estado durante una década). $[es obsoleto. El uso $[emite una advertencia de desaprobación incluso cuando no se activan las advertencias. Asignar cualquier cosa menos cero a $[será un error en 5.16. ¿Podemos dejar de mencionarlo $[ya?
ikegami
2
@Keith Thompson, mayor de 5.14, en realidad. Pero como dije, se ha desanimado y desaprobado durante mucho más tiempo que eso, y alguien que lo use $[sabría sus efectos.
ikegami
77
@ikegami: Sí, pero alguien que trata de entender la diferencia scalar @arry aún$#arr debe entender los posibles efectos de , aunque sean raros. $[
Keith Thompson el
41

Primero, el segundo no es equivalente a los otros dos. $#arraydevuelve el último índice de la matriz, que es uno menos que el tamaño de la matriz.

Los otros dos son prácticamente iguales. Simplemente está utilizando dos medios diferentes para crear un contexto escalar. Se trata de una cuestión de legibilidad.

Personalmente prefiero lo siguiente:

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

Lo encuentro más claro que

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

y

my $size = @array;
say $size;

Este último parece bastante claro solo así, pero encuentro que la línea adicional quita claridad cuando forma parte de otro código. Es útil para enseñar lo que @arrayhace en contexto escalar, y tal vez si desea usar $sizemás de una vez.

ikegami
fuente
15
Personalmente, prefiero la versión que usa la palabra clave "escalar", porque es bastante explícito que está forzando un contexto escalar. my $size=@arrayparece que podría ser un error donde se usó el sigilo incorrecto.
Nate CK
55
Esa es una muy mala idea. Las personas que usan scalarsin razón aprenden la lección equivocada. Empiezan a pensar que los operadores devuelven listas que pueden convertirse en escalares. Visto decenas de veces.
ikegami
2
¿Por qué es esto "sin razón"? Está utilizando scalarporque está obligando a la lista a un contexto escalar. Esa es la razón correcta para usarlo. Su ejemplo hace exactamente lo mismo, pero se basa en lo que hace Perl cuando evalúa una variable de lista en un contexto implícitamente escalar. Por lo tanto, su ejemplo requiere que el lector sepa sobre el comportamiento implícito de Perl en ese contexto. Solo está agregando una capa más de comportamiento implícito a la expresión, y Perl ya tiene demasiado comportamiento implícito que debe razonar para descifrar un programa.
Nate CK
2
@Nate CK, Re "¿Por qué esto es" no hay razón "? Estás utilizando scalarporque estás obligando a la lista a un contexto escalar", has demostrado mi punto sobre aprender la lección incorrecta. Esto es completamente falso. Ninguna lista es obligada por scalar. (Si lo hiciera, scalar(@array)y scalar(@array[0..$#array])devolvería lo mismo.) Le scalar(@array)dice @arrayque devuelva un escalar, que ya le dijo que hiciera my $size=.
ikegami
2
Lo creas o no, los desarrolladores tienen que depurar el código escrito por otros desarrolladores. Y los desarrolladores tienen que depurar el código que escribieron hace tres años.
Nate CK
27

Esto obtiene el tamaño al forzar la matriz a un contexto escalar, en el que se evalúa como su tamaño:

print scalar @arr;

Esta es otra forma de forzar la matriz a un contexto escalar, ya que se está asignando a una variable escalar:

my $arrSize = @arr;

Esto obtiene el índice del último elemento en la matriz, por lo que en realidad es el tamaño menos 1 (suponiendo que los índices comienzan en 0, que es ajustable en Perl, aunque hacerlo es generalmente una mala idea):

print $#arr;

Este último no es realmente bueno para usar para obtener el tamaño de la matriz. Sería útil si solo desea obtener el último elemento de la matriz:

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

Además, como puede ver aquí en Stack Overflow, esta construcción no se maneja correctamente por la mayoría de los resaltadores de sintaxis ...

Nate CK
fuente
2
Una nota al margen: solo use $arr[-1]para obtener el último elemento. Y $arr[-2]para obtener el penúltimo, y así sucesivamente.
tuomassalo
1
@tuomassalo: Estoy de acuerdo en que su sugerencia es un mejor enfoque. En retrospectiva, $#arrno es una característica muy útil, y no es casualidad que otros idiomas no la tengan.
Nate CK
6

Para usar la segunda forma, agregue 1:

print $#arr + 1; # Second way to print array size
jhoanna
fuente
for [0..$#array] { print $array[$_ ] } Sin embargo, funciona muy bien si el propósito de obtener el número de elementos es iterar a través de la matriz. La ventaja es que obtienes el elemento y un contador que están alineados.
Westrock
5

Los tres dan el mismo resultado si modificamos un poco el 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
fuente
55
¿Es esto algo diferente de lo que ya se ha mencionado en esta respuesta y en esta ?
devnull
5

Ejemplo:

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

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

La sección "Tipos de variables de Perl" de la documentación de Perlintro contiene

La variable especial $#arrayle dice el índice del último elemento de una matriz:

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

Es posible que tenga la tentación de usar $#array + 1para decirle cuántos elementos hay en una matriz. No te molestes. En la práctica, usar @arraydonde Perl espera encontrar un valor escalar ("en contexto escalar") le dará la cantidad de elementos en la matriz:

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

La documentación de Perldata también cubre esto en la sección "Valores escalares" .

Si evalúa una matriz en contexto escalar, devuelve la longitud de la matriz. (Tenga en cuenta que esto no es cierto para las listas, que devuelven el último valor, como el operador de coma C, ni para las funciones integradas, que devuelven lo que desean devolver). Lo siguiente siempre es cierto:

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

Algunos programadores eligen usar una conversión explícita para no dejar nada que dudar:

$element_count = scalar(@whatever);

Anteriormente en la misma sección se documenta cómo obtener el índice del último elemento de una matriz.

La longitud de una matriz es un valor escalar. Puede encontrar la longitud de la matriz @daysevaluando $#days, como en csh. Sin embargo, esta no es la longitud de la matriz; es el subíndice del último elemento, que es un valor diferente ya que normalmente hay un elemento 0.

Greg Bacon
fuente
2

Hay varias formas de imprimir el tamaño de la matriz. Aquí están los significados de todos: Digamos que nuestra matriz esmy @arr = (3,4);

Método 1: escalar

Esta es la forma correcta de obtener el tamaño de las matrices.

print scalar @arr;  # prints size, here 2

Método 2: número de índice

$#arrda el último índice de una matriz. entonces, si la matriz es de tamaño 10, entonces su último índice sería 9.

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

Estamos agregando 1 aquí considerando la matriz como 0 indexada . Pero, si no está basado en cero, entonces, esta lógica fallará .

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

El ejemplo anterior imprime 6, porque hemos establecido su índice inicial en 4. Ahora el índice sería 5 y 6, con los elementos 3 y 4 respectivamente.

Método 3:

Cuando se utiliza una matriz en contexto escalar, devuelve el tamaño de la matriz.

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

En realidad, el método 3 y el método 1 son iguales.

Kamal Nayan
fuente
2

De perldoc perldata , que debería ser seguro citar:

Lo siguiente siempre es cierto:

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

Siempre y cuando no $ $ lo que sea ++ y aumente misteriosamente el tamaño o su matriz.

Los índices de la matriz comienzan con 0.

y

Puede truncar una matriz a cero asignándole la lista nula (). Los siguientes son equivalentes:

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

Lo que me lleva a lo que estaba buscando, que es cómo detectar que la matriz está vacía. Lo encontré si $ # empty == -1;

jwal
fuente
1

¿Qué pasa int(@array)ya que amenaza el argumento como escalar?

reflexivo
fuente
0

Para encontrar el tamaño de una matriz, use la scalarpalabra clave:

print scalar @array;

Para averiguar el último índice de una matriz existe $#(variable predeterminada de Perl). Da el último índice de una matriz. Como una matriz comienza desde 0, obtenemos el tamaño de la matriz agregando uno a $#:

print "$#array+1";

Ejemplo:

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

Salida:

3

3
Sandeep_black
fuente