2009-05-14 30 views
27

¿Cómo obtengo el total de elementos en una matriz, NO la última identificación?Contando elementos de matriz en Perl

Ninguna de las dos maneras que encontré para hacer esto funciona:

my @a; 
# Add some elements (no consecutive ids) 
$a[0]= '1'; 
$a[5]= '2'; 
$a[23]= '3'; 

print $#a, "\n"; # Prints 23 
print scalar(@a), "\n"; # Prints 24 

que esperaba obtener 3 ...

Respuesta

39

Editar: Hash frente matriz

Como cincodenada señaló correctamente en el comentario, ysth dio una mejor respuesta: Debería haber respondido a su pregunta con otra pregunta: "¿Realmente desea utilizar una matriz de Perl ? Un hash puede ser más apropiado ".

Una matriz asigna memoria para todos los índices posibles hasta la más grande usada hasta ahora. En su ejemplo, asigna 24 celdas (pero usa solo 3). Por el contrario, un hash solo asigna espacio para los campos que realmente se usan.

solución de matriz: grep escalar

Aquí hay dos soluciones posibles (ver más abajo para una explicación):

print scalar(grep {defined $_} @a), "\n"; # prints 3 
print scalar(grep $_, @a), "\n";   # prints 3 

Explicación: Después de añadir $a[23], su matriz contiene realmente 24 elementos --- pero la mayoría de ellos no están definidos (lo que también se evalúa como falso). Puede contar la cantidad de elementos definidos (como se hizo en la primera solución) o la cantidad de elementos verdaderos (segunda solución).

¿Cuál es la diferencia? Si configura $a[10]=0, la primera solución contará, pero la segunda no (porque 0 es falso pero está definido). Si configura $a[3]=undef, ninguna de las soluciones lo contará.

solución hash (por yst)

Como sugiere otra solución, se puede trabajar con un hash y evitar todos los problemas:

$a{0} = 1; 
$a{5} = 2; 
$a{23} = 3; 
print scalar(keys %a), "\n"; # prints 3 

Esta solución cuenta con ceros y valores undef.

+0

Intentaré hash, gracias. – grilix

+1

La última parte de esta respuesta es la correcta. Grillix parece ser de un fondo de PHP. Lo que PHP llama "arreglos" en realidad son más parecidos a los valores hash de Perl, y el último debería usarse en casos como este. – cincodenada

+0

¿Cómo se puede extender esta idea a matrices multidimensionales en perl? – damned

8

de impresión escalar definido grep {$ _} @ un;

+5

Explicación: perl realmente no tiene matrices "dispersas" como grilix las quiere. Si dices "mi @a; $ a [10] = 5;" luego perl crea una matriz con 11 entradas: las primeras 10 se rellenan con 'undef', la 11a se llena con '5'. El informe "scalar @a" y "$ # a" siempre es el índice general de longitud/último. kcwu filtra la matriz para contar solo las entradas definidas. – user55400

+0

Bueno, funciona: P .. ¡Gracias! – grilix

+0

Funciona, pero no es bueno. La función grep es O (n), lo que significa que si tiene @a [1, 1_000_000] = (1, 2); luego tiene que ver cada uno de los 1,000,000 de artículos para contarte, también significa que estarás ocupando un montón de memoria sin ninguna razón, usa un hash en su lugar. –

14

Quizás desee un hash en su lugar (o además). Las matrices son un conjunto ordenado de elementos; si crea $foo[23], crea implícitamente $foo[0] a través de $foo[22].

16

Parece que quiere un sparse array. Una matriz normal tendría 24 artículos en ella, sino una matriz dispersa tendría 3. En Perl emular matrices dispersas con hashes:

#!/usr/bin/perl 

use strict; 
use warnings; 

my %sparse; 

@sparse{0, 5, 23} = (1 .. 3); 

print "there are ", scalar keys %sparse, " items in the sparse array\n", 
    map { "\t$sparse{$_}\n" } sort { $a <=> $b } keys %sparse; 

La función keys en contexto escalar devolverá el número de elementos de la matriz dispersa . El único inconveniente de usar un hash para emular una matriz dispersa es que debe ordenar las claves antes de iterar sobre ellas si su orden es importante.

También debe recordar utilizar la función delete para eliminar elementos de la matriz dispersa (simplemente no es suficiente establecer su valor en undef).

+0

Esto es correcto. Sin embargo, Tie :: IxHash es opcional; en tu ejemplo, parece innecesario. Además, no es necesario proporcionar el predicado para ordenar, ya que es el predeterminado. "sort keys% sparse" también funciona. – spoulson

+0

Whoops, The Tie :: IxHash queda de otro ejemplo. Déjame eliminar eso. –

+2

@Spoulson No el orden predeterminado es léxico no numérico, por lo que las claves (1, 2 y 10) se ordenarán (1, 10, 2). –

0
sub uniq { 
    return keys %{{ map { $_ => 1 } @_ }}; 
} 
my @my_array = ("a","a","b","b","c"); 
#print join(" ", @my_array), "\n"; 
my $a = join(" ", uniq(@my_array)); 
my @b = split(/ /,$a); 
my $count = $#b; 
+1

Este código tiene serios problemas. Primero son los principales, se rompe si los elementos en el conjunto contienen espacios. En segundo lugar, itera sobre el conjunto completo de elementos de la matriz una vez y el conjunto de elementos definidos dos veces. En tercer lugar, al igual que todas las soluciones basadas en matrices, no tiene forma de distinguir undefs del conjunto de usuarios frente a las ranuras vacías en la matriz (esta puede no ser mala dependiendo de cómo se use el código). –

2
@people = qw(bob john linda); 
$n = @people; # the number 3 
Print " le number in the list is $n \n"; 

Expresiones en Perl siempre devolver el valor apropiado para su contexto. Por ejemplo, qué tal el "nombre" * de una matriz. En un contexto de lista, proporciona la lista de elementos. Pero en un contexto escalar, devuelve la cantidad de elementos en la matriz:

Cuestiones relacionadas