2009-05-14 9 views
27

Come ottengo gli elementi totali in un array, NON l'ultimo ID?Conteggio degli elementi dell'array in Perl

Nessuno dei due modi che ho trovato per fare questo funziona:

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 

mi aspettavo di ottenere 3 ...

risposta

39

Edit: Hash contro Array

Come cincodenada giustamente sottolineato nel commento, ysth ha dato una risposta migliore: avrei risposto alla tua domanda con un'altra domanda: "Vuoi veramente usare un array di Perl ? Un hash può essere più appropriato. "

Una matrice alloca la memoria per tutti gli indici possibili fino al più grande finora utilizzato. Nel tuo esempio, assegni 24 celle (ma ne usi solo 3). Al contrario, un hash assegna solo spazio per quei campi che sono effettivamente utilizzati.

soluzione Array: grep scalare

Qui ci sono due soluzioni possibili (vedi sotto per la spiegazione):

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

Spiegazione: Dopo aver aggiunto $a[23], la matrice non contiene effettivamente 24 elementi --- ma la maggior parte di questi sono indefiniti (che viene valutato anche come falso). È possibile contare il numero di elementi definiti (come fatto nella prima soluzione) o il numero di elementi reali (seconda soluzione).

Qual è la differenza? Se si imposta $a[10]=0, la prima soluzione la conteggia, ma la seconda soluzione no (perché 0 è falso ma definito). Se imposti $a[3]=undef, nessuna delle soluzioni la conteggia.

soluzione Hash (da yst)

Come suggerito da un'altra soluzione, è possibile lavorare con un hash e di evitare tutti i problemi:

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

Questa soluzione conta gli zeri e dei valori undef.

+0

Proveremo gli hash, grazie. – grilix

+1

L'ultima parte di questa risposta è quella corretta. grillix sembra provenire da uno sfondo PHP. Quelli che PHP chiama "array" sono in realtà più simili agli hash di Perl, e quest'ultimo dovrebbe essere usato in casi come questo. – cincodenada

+0

Come può questa idea essere estesa ad array multidimensionali in perl? – damned

8

stampa scalare grep {$ _ definito} @a;

+5

Spiegazione: perl in realtà non ha array "sparsi" come li desidera Grilix. Se dici "my @a; $ a [10] = 5;" quindi perl crea un array con 11 voci: i primi 10 sono riempiti con 'undef', l'11 viene riempito con '5'. Che rapporto "scalar @a" e "$ # a" è sempre la lunghezza totale/l'ultimo indice. kcwu filtra la matrice per contare solo le voci definite. – user55400

+0

Bene, funziona: P .. Grazie! – grilix

+0

Funziona, ma non è buono. La funzione grep è O (n), il che significa che hai @a [1, 1_000_000] = (1, 2); quindi deve esaminare ciascuno dei 1.000.000 di elementi per ottenere un conteggio, ma significa anche che si sta prendendo un sacco di memoria senza motivo, utilizzare invece un hash. –

14

Forse vuoi un hash invece (o in aggiunta). Le matrici sono un insieme ordinato di elementi; se crei $foo[23], crei implicitamente $foo[0] tramite $foo[22].

16

Sembra che tu voglia un sparse array. Una matrice normale avrebbe 24 elementi in esso, ma una matrice sparsa avrebbe 3. In Perl emuliamo array sparsi con hash:

#!/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 funzione keys nel contesto scalare restituirà il numero di elementi nella matrice sparsa . L'unico svantaggio di usare un hash per emulare un array sparse è che devi ordinare le chiavi prima di iterarle sopra se il loro ordine è importante.

È inoltre necessario ricordare di utilizzare la funzione delete per rimuovere elementi dall'array sparse (è sufficiente impostare il loro valore su undef non è sufficiente).

+0

Questo è giusto. Tuttavia, Tie :: IxHash è facoltativo; nel tuo esempio sembra non necessario. Inoltre, non è necessario fornire il predicato per ordinare, poiché questo è il valore predefinito. anche "ordina i tasti% sparse". – spoulson

+0

Whoops, the Tie :: IxHash viene lasciato da un altro esempio. Lasciami rimuovere. –

+2

@Spoulson L'ordinamento predefinito non è lessicale né numerico, quindi le chiavi (1, 2 e 10) verranno ordinate (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

Questo codice ha seri problemi. Prima di tutto, è rotto se gli elementi nella matrice contengono spazi. In secondo luogo, itera su una serie completa di elementi dell'array una volta e sul set di elementi definiti due volte. In terzo luogo, come tutte le soluzioni basate su array, non ha modo di distinguere undefs il set utente e gli slot vuoti nell'array (questo potrebbe non essere negativo a seconda di come viene usato il codice). –

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

espressioni in Perl sempre restituire il valore appropriato per il loro contesto. Ad esempio, che dire del "nome" * di un array. In un contesto di lista, fornisce l'elenco degli elementi. Ma in un contesto scalare, restituisce il numero di elementi nell'array: