Perl/Variabili vettori

Indice del libro


I vettori o array si possono immaginare come un treno. Ogni treno ha un certo numero di vagoni.

Analogamente gli array sono in insieme di scalari.

Come nel treno le carrozze sono numerate, così negli array per identificare una informazione si usa un numero intero.

La numerazione parte da 0 ed arriva fino al numero di elementi - 1.

Quindi un vettore con 5 elementi :

  • la prima "carrozza" sarà identificata con il numero 0 (e non 1)
  • l'ultima "carrozza" sarà identificata con il numero 4

infatti 0,1,2,3,4 sono 5 elementi.

Vediamo un altro esempio di 100 elementi:

treno - vagoni  : 1 2 3 4 5 ... 100

array - scalari : 0 1 2 3 4 ... 99

Il nome

modifica

Come per le variabili scalari , per identificare una variabile vettore (più valori in fila) occorre anteporre al nome il carattere @ (sigillo). Il nome di una variabile DEVE iniziare con "lettere", "_" , "'", mentre dal secondo carattere oltre ai precedenti si possono usare i "numeri" fino ad un massimo di 256 caratteri. NOTA: Essendo un linguaggio "case sensitive" le lettere maiuscole e le lettere minuscole sono differenti.

 @a; # è il vettore a
 @A; # è il vettore A diverso da a

NOTA: il nome di un vettore non può iniziare con numeri !!!

Il contenuto

modifica

Il contenuto è un qualsiasi scalare.

Vediamo la sintassi per creare un array:

 @a;           #Ho definito un array ma non l'ho riempito
 @a = ();      #Ho definito un array ed è vuoto
 # PRIMO ARRAY
 @a = ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 );
               #Ho definito un array ed è riempito con  9 valori da 1 a 9 
               #     che occupano le posizioni da 0 a 8 ! 
 # SECONDO ARRAY
 @b = ( 4 , "pippo" , 1 , "pluto" , 2 , "paperino" , 3 , "minni" , 4 );
               #Ho definito un array ed è riempito con  9 valori fra stringhe e numeri 
               #     che occupano le posizioni da 0 a 8 ! 
 # TERZO ARRAY
 $lun = "lunedì";
 $mar = "martedì";
 @c = ( $lun , $mar , "mercoledì" , "giovedì" , "venerdì" , "sabato" , "domenica" );
               #Ho definito un array ed è riempito con  7 valori di stringhe 
               #     che occupano le posizioni da 0 a 6 !

Per poter usare i valori dell'array occorre poter selezionare il dato singolo. Per far questo si utilizza il metodo dell'indice. L'indice rappresenta la posizione del dato. Nel nostro caso la sintassi prevede l'uso delle parentesi quadre come identificatore dell'indice. Vediamo ora se volessi scrivere il terzo valore dell'array (è alla posizione 2 perché si conta da 0):

 print "posizione 3 primo array :$a[2]\n"; 
 print "posizione 3 secondo array :$b[2]\n"; 
 print "posizione 3 terzo array :$c[2]\n";

questo scriverà : 3 per il primo array, 1 per il secondo array, mercoledì per il terzo array.

Notare che la gestione dei simboli è corretta: se intendo gestire l'array nella sua "totalità" uso il simbolo @ mentre se ne voglio un elemento, quindi una variabile scalare, allora uso "$" con il nome del vettore e l'identificatore della posizione racchiuso fra parentesi quadre.

Il Perl ha adottato la particolarità del contesto per sapere di quanti elementi è composto un array:

   $numero_elementi = @a;
 print "numero di elementi di primo array e' : $numero_elementi\n";

Tuttavia esiste una sintassi specifica per sapere il valore dell'ultimo indice o per "forzare" la quantità di elementi di un array:

   $numero_elementi = $#a;
 print "numero di elementi di primo array e' : $numero_elementi\n";

Mentre se si usa l'istruzione:

   $#a = 10;

Ora @a ha ben 10 elementi, di scalari di valore undef.

NOTA se l'array ha un numero inferiore di elementi rispetto a quelli presenti , gli elementi che sono stati "aggiunti" hanno valore undef.

Linerizzazione

modifica

Con questa parola intendo la "trasformazione" che il linguaggio opera automaticamente nel trattare nel contesto gli array. Vediamo questo esempio:

 @a = ( 2 , 3 , 4 );
 @b = ( 1 , @a , 5 , 6 );

Nell'esempio trattato, @b ha i valori ( 1 , 2 , 3 , 4 , 5 , 6 ), quindi al posto di @a sono stati inseriti i suoi valori. Quindi in @a non è stato messo il numero di elementi di @a ma gli elementi stessi che costituiscono il vettore. Questo che può apparire strano in realtà è molto utile per "sommare" elementi e giuntarli. Se si volesse inserire un array è necessario mettere un reference (e quindi lo scalare che punta alle informazioni di "tipo" array). Se si volesse mettere il numero di elementi di un array è obbligatorio usare $#a.

Notazione [ x , y , z ] e [ x .. y ]

modifica

In Perl esiste la possibilità di estrarre o trattare contemporaneamente più informazioni da un array. Questo è possibile perché è possibile identificare sinteticamente più informazioni.

  1. nel caso della notazione [ x , y , z ] si indicano gli elementi alla posizione x, y, z (nell'esempio sono 3, ma possono essere di più o di meno!).
  2. nel caso della notazione [ x .. y ] si indicano tutti gli elementi che vanno dall'elemento x a quello y.

Se gli elementi x e y sono numeri, la notazione indica tutti i numeri (distanziati da un'unità) che intercorrono fra x e y. Invece, nel caso di lettere (stringhe) sono tutti i caratteri fra la prima lettera (stringa) e l'altra: 'a' .. 'f' equivale ad a, b, c, d, e, f.

 @alfabeto = ('A' .. 'Z');
 @giorni_del_mese = ('01' .. '31');
 @ACD = @alfabeto[0 , 2 ,3 ];
 @s = ();
 @s[2,3,5] = ( 'PIPPO' , 'pluto' , 'CIAO' );
 @k[0 .. 1] = ( 'mario' , 'giuseppe' );

in @alfabeto ci saranno tutte le lettere dalla A alla Z

in giorni del mese ci saranno tutti i numeri da 01 a 31 (compreso 05, 11 , 21 etc)

in @ACD contiene ( 'A' , 'C' , 'D' ) prelevate da alfabeto dalle posizioni 0,2,3

in @s contiene ( undef , undef , 'PIPPO' , 'pluto' , undef , 'CIAO' )

in @k contiene ( 'mario' , 'giuseppe' ) NOTA: in quest'ultimo assegnamento lo si poteva ottenere anche con il seguente codice:

 @k = ( 'mario' , 'giuseppe' );

Funzioni per immettere informazioni nei vettori

modifica

Oltre ai metodi precedentemente esposti è possibile utilizzare delle funzioni che trattano i vettori come file dalle quali estrarre informazioni dall'inizio o dalla coda Le funzioni sono push, pop, shift e unshift.

  • push e pop lavorano sulla "coda del treno".
  • shift e unshift lavorano sulla "testa del treno".
  • push mette le informazioni in fondo
  • pop estrae le informazioni dal fondo
  • shift estrae le informazioni dalla testa
  • unshift mette le informazioni dalla testa
 @a = ( 2 , 3, 4, 5 );
 push ( @a , 6 , 7 );     #ora @a contiene ( 2 , 3, 4, 5 , 6 , 7 ) 
 $b = pop (@a);           # $b = 7 ,  @a contiene ( 2 , 3, 4, 5 , 6 )
 $c = shift ( @a );       # $c = 2 ,  @a contiene ( 3, 4, 5 , 6 )
 unshift( @a , 0 , 1, 2); # ora @a contiene ( 0 , 1, 2 , 3, 4, 5 , 6 )

Da array a stringa e viceversa

modifica

Oltre al modo "puntatore" $nome[posizione] è possibile passare da una stringa ad un vettore utilizzando due funzioni che trattano il vettore/stringa nel suo complesso:

  • join consente di aggregare i dati di un vettore in stringa
  • split consente di "separare" una stringa ed ottenere un vettore

In particolare join "unisce" i valori dell'array mettendo fra loro la stringa indicata dall'utente:

 @a = ( 1 , 2, 3 );
 print join("_" , @a); # scrive 1_2_3
 print "\n";

NOTA: se l'array passato non ha elementi torna una stringa vuota.

Mentre per split il discorso è più articolato in quanto come elemento separatore accetta una espressione regolare che al momento è prematuro introdurre. Semplificando si può dire che accetta una stringa che risulta essere il separatore. Limitando l'esempio a strighe statiche :

 @a = split ( " " , "questo testo verrà diviso in ogni parola" );
 print @a."\n";

quindi in @a avremo ( "questo" , "testo" , "verrà" , "diviso" , "in" , "ogni" , "parola" ) per fare l'operazione contraria basterà scrivere:

 $a = join( " " , @a );

Uso di qw/.../

modifica

Come per gli scalari si è visto l'uso di q/.../ e qq/.../ così è stato introdotto per i vettori qw/.../. In pratica consente di assegnare ad un vettore le singole stringhe separate da spazio presenti al posto dei puntini. Esempio:

 @a = qw( ma che bella questa funzione ); #@a conterrà "ma","che","bella,"questa","funzione"

Questa funzione consente di cancellare un dato da un array.Tuttavia, se non è all'ultima posizione, non riduce la dimensione dell'array.

 @p = split ( " " , "questo testo verrà diviso in ogni parola" );
 $c = delete ( $p[3] );
 print "$c , ".join("_" , @p)."\n";

che mostrerà:

diviso , questo_testo_verrà__in_ogni_parola

NOTA: da notare lo "__" fra la parola "verrà" e la parola "in" : in quel punto c'è un elemento undef e quindi vengono aggiunti 2 "_" (uno per il valore "undef" e uno per il valore "in")

Dopo tanta teoria un po' di pratica

modifica

Vediamo ora una soluzione ottenibile con le informazioni finora trattate.

ESEMPIO1 Assegnare ad un vettore i numeri da 1 a 12.

 @numeri = ( 1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 );

ESEMPIO2 Assegnare ad un altro vettore i nomi dei mesi usando la funzione split.

 @mesi   = split ( " " , 'gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre" );

ESEMPIO3 Scrivere il dato corrispondente alla terza posizione del vettore precedente.

 print $mesi[2]."\n";

nota: il terzo mese ha le informazioni alla posizione 2 nel vettore (si parte da 0 a contare: 0 1 2 ).

ESEMPIO4 Dati due array: uno con numerazione da 1 a 12, l'altro con il nome dei mesi, scrivere i dati relativi al mese numero 3 nella seguente forma: "il mese " + numero del mese + "ha il nome: " + il relativo nome.

 @numeri = ( 1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 );
 @mesi   = split ( " " , 'gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre" );
 $meseDaScrivere = 3;
  
  
 print join(" " 
            , "il mese " 
            , $numeri[$meseDaScrivere -1] # il numero del mese 
            , "ha il nome: " 
            , $mesi[$meseDaScrivere -1]   # nome del mese
            )."\n";

nota: si è usato "$meseDaScrivere -1" perché il vettore iniziando a contare da 0, il mese 3 ha le informazioni alla posizione 2 nel vettore.

Riassunto

modifica

I vettori:

  1. sono identificati dal sigillo "@" davanti al nome
  2. contengono uno o più valori scalari
  3. si ottengono/assegnano i dati (scalari) utilizzando la sintassi $'nome'['posizione']
  4. si utilizzano le funzioni pop, push, shift, unshift per mettere togliere elementi
  5. si utilizzano le funzioni join, split per "passare" da stringa a vettore e viceversa