Perl/Variabili hash

Indice del libro


Gli array associativi o hash si possono immaginare come dei vettori che hanno i vagoni individuati da "un nome", piuttosto che da un numero. Analogamente agli array, quindi, rappresentano un insieme di scalari; a differenza dei vettori, in cui nel treno le carrozze sono numerate, negli hash, per identificare un'informazione, si usa un "nome". Non esiste però alcun modo di legare l'ordine di immissione dei dati e il loro successivo recupero. L'unica garanzia è che ogni "nome" assegnato al un vagone (chiave-key) corrisponde uno ed un unico valore (valore-value).

Il nome

modifica

Come per le variabili scalari, lo stesso si può dire per i nomi degli hash. Per identificare una variabile hash, occorre anteporre al nome il carattere %. 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. Infine, essendo un linguaggio "case sensitive", le lettere maiuscole vengono considerate differenti dalle lettere minuscole.

%a; # è la variabile a
%A; # è la variabile A diversa da a

NOTA: il nome di una variabile non può iniziare con numeri !!!

Il contenuto

modifica

Il contenuto è un qualsiasi scalare.

A differenza del vettore, l'hash è un elemento che associa ad UNA stringa (detta chiave) UN valore. Quindi non è possibile avere più chiavi con lo stesso nome nello stesso hash.

Vediamo la sintassi per creare un hash:

%a;           #Ho definito un hash ma non l'ho riempito
%a = ();      #Ho definito un hash ed è vuoto !
%a = (      mario => 'maria'
      , giancarlo => 'giancarla'
      ,   carmelo => 'carmela'); # ho definito un hash con una array e associazioni "chiare"
%a = ( 'mario' , 'maria' , 'giancarlo' , 'giancarla' , 'carmelo' , 'carmela' ); # ho definito un hash con un vettore

In questo modo ho associato alla chiave mario => il valore maria , alla chiave giancarlo => il valore giancarla e alla chiave carmelo => il valore carmela.

NOTA: Per definire un hash si usa un vettore. Tuttavia mentre un vettore è una "fila" di valori, l'hash è una associazione chiave => valore.

Per ottenere il valore associato ad una chiave si usa questa forma:

print $a{mario}."\n";

che mostrerà "maria". Come si può notare il costrutto $a{<nome>} non è equivoco ed identifica in modo assoluto l'unico valore associato a <nome>. Da notare che i sigilli rimangono coerenti : l'elemento associato a <nome> è uno scalare !!!.

Ricordo nell'hash non è possibile attribuire più di un valore ad una stessa chiave, quindi le chiavi sono univoche dentro uno stesso hash

Gestire gli array associativi

modifica

Abbiamo detto che gli array associativi usano "key" associate a "value". Vediamo ora come "gestire" queste entità.

Per ottenere l'elenco delle chiavi si usa keys

print (keys %a)."\n";

che torna l'elenco di tutte le chiavi che compongono %a. Da notare che è sicuro che ci siano tutte le chiavi ma l'ordine non è mai assicurato.

Per ottenere i valori si usa values

print (values %a)."\n";

che torna l'elenco di tutti i valori che compongono %a. Da notare che è sicuro che ci siano tutti i valori ma l'ordine non è mai assicurato.

entrambe queste funzioni ritornano un array composto di tutte le informazioni richieste di %a (key o value).

Vediamo ora un'istruzione che, ogni volta che viene invocata, ritorna un elemento dell'array associativo:

($key, $value) = each %a;

Vediamo questo esempio:


%contact = ( mario => '0220202020'
           , pippo => '0330303030'
           , alfa  => '0440404040'
           );
($key, $value) = each %contact;
print "key:$key ,value:$value\n";

($key, $value) = each %contact;
print "key:$key ,value:$value\n";

($key, $value) = each %contact;
print "key:$key ,value:$value\n";

che scriverà ogni chiave valore presente in %contact. Da notare che è sicuro che ogni volta "each" torni un nuovo valore presente in %contact ma l'ordine non è mai assicurato.

exists e delete

modifica

Queste due funzioni consentono:

  1. di verificare se un certo dato esiste
  2. di poter cancellare un certo dato.

Quindi usando exists è possibile verificare la presenza di una chiave:

%a = (      mario => 'maria'
      , giancarlo => 'giancarla'
      ,   carmelo => 'carmela');
print (exists $a{mario})." , ".(exists $a{beppe})."\n";

che mostrerà:

1 , 0

Mentre, usando delete, come per gli array, è possibile togliere una corrispondenza chiave => valore :

%a = (      mario => 'maria'
      , giancarlo => 'giancarla'
      ,   carmelo => 'carmela');


$b = delete ( $a{mario} );
print "b=$b , %a:".join(" , " ,(keys %a))."\n";

che mostrerà:

b=maria , %a:giancarlo , carmelo

Notazione { x , y , z }

modifica

Come per i vettori, anche per gli hash esiste una notazione che consente di trattare più informazioni su uno stesso hash.

%lettere = ( a => 'A', b => 'B' , c => 'C' , d => 'D' );
@lettere{ e , f , g } = ( 'E' , 'F' , 'G' );
print "lettere di e :$lettere{e}\n";

che mostrerà:

lettere di e :E


DA NOTARE che, nel secondo assegnamento, il sigillo di lettere è cambiato da % a @: dato che si tratta di più valori ($lettere{e},$lettere{f},$lettere{g}) è obbligatorio mettere @ e non %. Se ci si riflette un attimo l'array ( 'E' , 'F' , 'G' ) contiene solo i valori e deve corrispondere ad un array.Nel caso ci fosse stato il sigillo % le chiavi devono essere nell'array di destra.

Dopo tanta teoria un po' di pratica

modifica

Vediamo ora una soluzione ottenibile con le informazioni finora trattate.

ESEMPIO1 Assegnare ad un hash i numeri da 1 a 12 e i corrispondenti mesi.

Soluzione1 - esplicita -

%h = ( 1 => 'gennaio'
     , 2 => 'febbraio'
     , 3 => 'marzo'
     , 4 => 'aprile'
     , 5 => 'maggio'
     , 6 => 'giugno'
     , 7 => 'luglio'
     , 8 => 'agosto'
     , 9 => 'settembre'
     , 10 =>'ottobre'
     , 11 =>'novembre'
     , 12 =>'dicembre'
     );

Soluzione2 - dall'esempio degli array -

@h {1 .. 12} = split ( " " , 'gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre" );

Soluzione3 - al risparmio -

@h {1 .. 12} = qw( gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre );

ESEMPIO2 Scrivere il dato (nome mese) corrispondente alla chiave (posizione, numero) 3.

print $h{3}."\n";

nota: il terzo mese ha le informazioni associate alla chiave '3' e non è più importante la posizione come per gli array.

ESEMPIO3 Dato l'array precedente scrivere i dati relativi al mese numero 3 nella seguente forma:"il mese " il numero del mese seguito da "ha il nome :" il relativo nome.

$meseDaScrivere = 3;
print "il mese ". $meseDaScrivere            # numero del mese
     ." ha il nome: ". $h{$meseDaScrivere}   # nome del mese
     ."\n";


Riassunto

modifica

Gli hash:

  1. sono identificati dal sigillo "%" davanti al nome
  2. contengono valori scalari associati a chiavi (stringhe)
  3. si ottengono/assegnano i dati (scalari) utilizzando la sintassi $'nome'{'posizione'}
  4. si utilizzano le funzioni keys , values avere l'elenco degli elementi
  5. si utilizza la funzione exists per sapere se c'è una chiave.