Array

8. Array multidimensionali e associativi

Array multidimensionali

Come abbiamo visto nel capitolo precedente, un normale array contiene all'interno dei suoi elementi, valori semplici come numeri interi, stringhe e così via.

Un array può però contenere a sua volta un altro array, dando vita ad un array multidimensionale.

Abbiamo vari modi per inizializzare un array multidimensionale, vediamo di seguito quattro blocchi di codice equivalenti, che svolgono cioè la medesima operazione :

dati.push(new Array("mario", "rossi", "roma"));
dati.push(new Array("luca", "verdi", "milano"));

dati.push(["mario", "rossi", "roma"]);
dati.push(["luca", "verdi", "milano"]);

dati[0] = new Array("mario", "rossi", "roma");
dati[1] = new Array("luca", "verdi", "milano");

dati[0] = ["mario", "rossi", "roma"];
dati[1] = ["luca", "verdi", "milano"];

Vediamo ora un esempio completo utilizzando la vecchia Classe documento HelloWorld :

package
{
	import flash.display.MovieClip;

	public class HelloWorld extends MovieClip
	{
		public function HelloWorld():void
		{
			var dati:Array = new Array();

			dati[0] = new Array("mario", "rossi", "roma");
			dati[1] = new Array("luca", "verdi", "milano");

			trace(dati[0][2]); // Output : roma
			trace(dati[1][1]); // Output : verdi
		}
	}
}

Concettualmente esiste un altro modo per memorizzare dati multidimensionali negli array, ossia inserendo istanze di oggetti, comunemente istanze della classe Object, ma ricordate che potete sempre memorizzarvi qualunque istanza di una qualunque classe.

Essendo Object la classe base in ActionScript 3, essa sarà utilizzata di default ogni volta che non sarà specificato altrimenti.

Il codice che segue inizializza un Array "dati" e inserisce nel primo elemento un'istanza di Object con tre attributi :
nome, cognome e residenza.

Per il secondo elemento viene mostrato un altro metodo per eseguire la medesima operazione.

var dati:Array = new Array();

dati[0] = {nome: "Mario", cognome: "Rossi", residenza: "Roma"};
dati.push({nome: "Luca", cognome: "Verdi", residenza: "Milano"});

trace(typeof(dati[0])); // Output : object
trace(dati[1].residenza); // Output : Milano

Nel caso in cui non vogliate che venga usata un'istanza di Object, ma bensì di una vostra classe, allora procedete come segue :

var dati:Array = new Array();

dati[0] = new MiaClasse();

dati[0].attributo1 = "valore";
dati[0].attributo2 = "valore";

Array associativi

Fino ad ora abbiamo visto degli array la cui posizione degli elementi veniva identificata tramite un'indice numerico di tipo int.

In ActionScript 3 è possibile creare un altro tipo di array, anche essi volendo multidimensionali, la cui posizione degli elementi viene indicata però con una stringa (chiave), dando vita ad un Array associativo.

Parlando di array associativi, è abitudine nella programmazione dare un altro nome agli indici che indicano la posizione degli elementi, chiamandoli chiavi.

Ma vediamo un frammento di codice più semplice dove mostrerò la corretta sintassi per inizializzare un array associativo :

var dati:Array = new Array();

dati["nome"] = "Mario";
dati["cognome"] = "Rossi";
dati["residenza"] = "Roma";

for (var chiave:String in dati)
	trace(chiave + " = " + dati[chiave]);

/* Output

nome = Mario
cognome = Rossi
residenza = Roma */

Il costrutto for in verrà spiegato in dettaglio nei capitoli seguenti, per il momento ci basti sapere che ci consente di scorrere un array considerando ogni elemento che esso contiene.

Per utilizzare un array associativo in maniera multidimensionale, la sintassi è la stessa vista in precedenza :

var dati:Array = new Array();

dati["impiegato"] = ["Mario", "Rossi"];
dati["stipendio"] = [1200, "euro"]

for (var chiave:String in dati)
	trace(chiave + " = " + dati[chiave][0] + " " + dati[chiave][1]);

/* Output

impiegato = Mario Rossi
stipendio = 1200 euro */

7. Array

Gli Array sono un tipo di dato particolare, in quanto ci consentono di racchiudere sotto ad un nome comune una collezione di variabili.

Il punto di forza degli array è quello di consentirci in poche righe di codice, di effettuare delle iterazioni per scorrere i dati contenuti nell'array, permettendoci quindi di gestire con facilità liste di elementi anche complessi.

Anche in questo caso come per le stringhe, il tipo di dato array viene gestito come nativo, mettendoci a disposizione sia gli operatori classici, come quello di accesso [] agli elementi, che la classe Array stessa.

Vediamo direttamente la sintassi corretta utilizzando il tipo di dato come un'istanza della classe Array :

var iscritti:Array = new Array(3); // Crea un array vuoto di 3 elementi
iscritti[0] = "Utente 1"; // Memorizza la stringa "Utente 1" nel primo elemento dell'array
iscritti[1] = "Utente 2"; // Memorizza la stringa "Utente 2" nel secondo elemento
iscritti[2] = "Utente 3"; // Memorizza la stringa "Utente 3" nel terzo elemento

/* La funzione "push" inserisce la stringa "Utente 4"

alla fine dell'array, quindi alla quarta posizione */
iscritti.push("Utente 4");

trace(iscritti); // Output : Utente 1, Utente 2, Utente 3, Utente 4
trace(iscritti.length); // Output : 4

Osservando il codice soprastante si può dedurre che il conteggio degli elementi inizia dalla posizione zero, quindi il primo elemento è accessibile attraverso l'istruzione array[0].

Anche la classe Array come String, deriva da Object e possiede l'attributo length, che indica il numero di elementi di cui è composto l'array.


Classe Array

Di seguito una lista dei metodi che ritengo di maggiore importanza e che mi sono trovato ad utilizzare più spesso :

  • concat() - Concatena gli elementi specificati all'array da cui è stato chiamato il metodo.
    Se un parametro è un altro array, ne vengono concatenati tutti gli elementi prima di passare al parametro successivo.
  • forEach() - Prende come parametro una funzione che sarà eseguita su ogni elemento dell'array.
  • indexOf() - Restituisce l'indice della prima occorrenza dell'elemento specificato.
  • join() - Unisce gli elementi dell'array in una stringa, separandoli con il delimitatore specificato.
  • pop() - Restituisce l'ultimo elemento dell'array rimuovendolo.
  • shift() - Restituisce il primo elemento dell'array rimuovendolo.
  • push() - Aggiunge elementi alla fine dell'array restituendo la nuova dimensione.
  • unshift() - Aggiunge elementi all'inizio dell'array restituendo la nuova dimensione.
  • slice() - Prende come parametri un'indice di inizio e uno di fine, che stabiliranno la porzione da cui creare e restituire un nuovo array.
  • sort() - Ordina gli elementi di un array.
  • sortOn() - Ordina gli elementi di un array in base a uno o più elementi di esso.
  • splice() - Modifica l'array aggiungendo o rimuovendo elementi da esso.

Esempio con concat()

var numeri:Array = new Array(1, 2, 3);
var lettere:Array = new Array("a", "b", "c");
var frutti:Array = new Array("pera", "banana", "cocco");

var unione:Array = numeri.concat(4, lettere, "d", frutti);

trace(unione); // Output : 1,2,3,4,a,b,c,d,pera,banana,cocco
trace(unione.length); // Output : 11

La classe Array inoltre possiede due costruttori.

Il primo costruttore prende come parametro un numero intero che stabilisce la dimensione dell'array, e viene chiamato se si specifica un solo parametro di tipo int o se non viene specificato alcun parametro, impostando in quest ultimo caso un array di zero elementi.

Il secondo costruttore invece, prende uno o N parametri che saranno considerati in modo ordinato come gli elementi del nuovo array.
Questo costruttore viene richiamato se viene specificato più di un parametro o se il primo parametro non è un numero intero.

Consideriamo il seguente codice :

var iscritti:Array = new Array(); // Chiama il primo costruttore
var iscritti:Array = new Array(3); // ... primo costruttore
var iscritti:Array = new Array("3"); // ... secondo costruttore
var iscritti:Array = new Array(3, 5); // ... secondo costruttore
var iscritti:Array = new Array(null); // ... secondo costruttore
  1. Effettua una chiamata al primo costruttore, inizializzando un array di zero elementi.
  2. Chiama ancora il primo costruttore, inizializzando un array vuoto di tre elementi.
  3. Chiama il secondo costruttore, creando un array di un solo elemento. Questo elemento avrà il valore "3" di tipo String.
  4. Chiama il secondo costruttore, creando un array di due elementi. Questi due elementi saranno i numeri interi 3 e 5.
  5. Chiama nuovamente il secondo costruttore inizializzando un array di un elemento, il quale avrà il valore null.

Ricordate che negli array potete memorizzare anche dati complessi, quindi istanze di classi a cui potrete accedere col metodo classico :

var dati:Array = new Array();
dati.push(new String("Flash CS3"));
dati.push(new String("ActionScript 3"));

trace(dati[0].length); // Output : 9
trace(dati[1].length); // Output : 14

36. Overload dell'operatore di accesso degli Array

Un'altra caratteristica che rende molto versatile PHP 5 è l'overloading dell'operatore di accesso degli Array : []

Per effettuare questo overload è necessario far sì che le nostre classi implementino l'interfaccia nativa ArrayAccess.
Quest'ultima fornisce i metodi astratti che ci permetteranno di utilizzare le istanze delle nostre classi come se fossero degli array omettendo quindi il classico operatore di selezione -> con i vantaggi che ne derivano dalla gestione di un array :

<?php

	class Oggetto implements ArrayAccess
	{
		public $attributo1 = "ciao";
		public $attributo2 = "pippo";

		/* Ridefinizione dei metodi di ArrayAccess
		
		...
		
		*/
	}

	$obj = new Oggetto();

	echo $obj["attributo1"] . " " . $obj["attributo2"]; // Stampa "ciao pippo"

?>

Vediamo cosa contiene l'interfaccia ArrayAccess prima di illustrare l'overload vero e proprio e le sue potenzialità.

interface ArrayAccess

  • bool offsetExists ($index)
  • mixed offsetGet ($index)
  • void offsetSet ($index, $new_value)
  • void offsetUnset ($index)

offsetExists viene richiamato per verificare se esiste l'indice specificato nel nostro pseudo-array.

offsetGet è invocato quando si tenta di leggere un valore all'indice specificato.

offsetSet è chiamato quando si tenta di scrivere un valore all'indice specificato.

offsetUnset è invocato quando si tenta di cancellare un valore all'indice specificato.


Esempio ArrayAccess

Di seguito un esempio dove mostrerò come unire le potenzialità di un oggetto al pratico sistema di gestione degli array.

Il codice nell'esempio ovviamente è solo parzialmente scritto in quanto serve solo a far capire il funzionamento di questo overload.

Ho creato una classe Impiegati che rappresenta una lista di impiegati e i lori stipendi gestita come se fosse un array, ma essendo anche un oggetto potrà vantare altri metodi per avviare operazioni più complesse come la stampa su schermo dell'intera lista degli impiegati o il salvataggio di quest'ultima su un file esterno.

<?php

	class Impiegati implements ArrayAccess
	{
		private $lista;

		public function Impiegati()
		{
			$this->lista = array();
		}

		private function convertiChiave($chiave)
		{ return ucwords(strtolower($chiave)); }

		function offsetExists($nome)
		{
			/* Converto la chiave dell'array assicurandomi che sia sempre minuscola
			con la sola iniziale maiuscola in modo da rendere gli accessi case-insensitive

			NOTA : le chiavi degli array nel linguaggio nativo sono invece case-sensitive */

			$nome = $this->convertiChiave($nome);

			foreach ($this->lista as $chiave => $valore)
				if ($chiave == $nome)
					return true;

			return false;
		}

		function offsetGet($nome)
		{
			$nome = $this->convertiChiave($nome);

			if ($this->offsetExists($nome))
				return $this->lista[$nome];
			else
				return NULL;
		}

		function offsetSet($nome, $valore)
		{
			$nome = $this->convertiChiave($nome);
			$this->lista[$nome] = $valore;
		}

		function offsetUnset($nome)
		{
			$nome = $this->convertiChiave($nome);

			if ($this->offsetExists($nome))
				$this->lista[$nome] = "Licenziato";
		}

		public function mostraStipendi()
		{
			foreach ($this->lista as $chiave => $valore)
			{
				if ($valore == "Licenziato")
				{ echo "$chiave è stato $valore<br />\n"; }
				else
				{ echo "$chiave ha uno stipendio di $valore euro<br />\n"; }
			}
		}

		public function salvaSuFile($nomefile)
		{
		    /* Codice per salvare la lista degli impiegati su file

		    ...

		    */
		}
	}

	$impiegati = new Impiegati();

	$impiegati["Mario"] = 1250;
	$impiegati["Luca"] = 2300;
	$impiegati["Giovanni"] = 1570;
	$impiegati["MARIO"] = 3740; // Sovrascrive "Mario" perchè converto sempre la chiave : ucwords(strtolower($chiave))

	// Licenzia Luca
	unset($impiegati["Luca"]);

	$impiegati->mostraStipendi();

?>

L'esempio produce il seguente risultato :

Mario ha uno stipendio di 3740 euro
Luca è stato Licenziato
Giovanni ha uno stipendio di 1570 euro


9. Array multidimensionali

Vediamo ora gli array multidimensionali e un metodo per gestirli.

Immaginate un array multidimensionale, come un array che contiene altri array.
Anche qui non c'è un limite preciso alla dimensione che può assumere un array multidimensionale, ma vediamo subito un esempio per farvi capire di che si tratta.

Immaginate di dover mettere in un unico array una serie di dati di questo genere :

ID Nome Cognome Settore Stipendio
1 Mario Rossi Design 1.250
2 Giacomo Bernardini Progettazione 1.550
3 Luca Manfredi Marketing 1.350

Un buon metodo per inserire questi dati in un array, è utilizzare un indice per la prima dimensione, ed una chiave per la seconda dimensione (N.B. : potete usare anche 3 dimensioni e vedere la base di dati come un cubo, ma non è questo il caso del nostro esempio).

$impiegati[1]["nome"] = "Mario";
$impiegati[1]["cognome"] = "Rossi";
$impiegati[1]["settore"] = "Design";
$impiegati[1]["stipendio"] = 1250;

$impiegati[2]["nome"] = "Giacomo";
$impiegati[2]["cognome"] = "Bernardini";
$impiegati[2]["settore"] = "Progettazione";
$impiegati[2]["stipendio"] = 1550;

$impiegati[3]["nome"] = "Luca";
$impiegati[3]["cognome"] = "Manfredi";
$impiegati[3]["settore"] = "Marketing";
$impiegati[3]["stipendio"] = 1350;

echo "<table width=\"600\" border=\"0\" cellspacing=\"5\" cellpadding=\"1\">\n";

for ($i = 1; $i <= count($impiegati); $i++)
{
	echo "\t<tr>\r";

	while (list($chiave, $valore) = each($impiegati[$i]))
	{
		$chiave = mb_convert_case($chiave, MB_CASE_TITLE);
		// La funzione sopra converte la prima lettera di $chiave in Maiuscola
		echo "\t\t<td>$chiave : $valore</td>\r";
	}

	echo "\t</tr>\r";
}

echo "</table>\n";

Il codice produce questo risultato.
I caratteri di escape "\n", "\t" e "\r", li ho usati per dare un indentazione e una formattazione ordinata al sorgente della pagina HTML che PHP produce, ottima abitudine per velocizzare le fasi di debug.

Infine vediamo la semplice ma efficace "array_search()".

$array = array();

array_push($array, "mela");
array_push($array, "fragola");
array_push($array, "limone");
array_push($array, "fragola");
array_push($array, "melone");
array_push($array, "fragola");
array_push($array, "limone");

echo array_search("fragola", $array) . "<br />\n";
echo array_search("limone", $array) . "<br />\n";
echo array_search("mela", $array) . "<br />\n";
echo array_search("anguria", $array) . "<br />\n";

Il codice produce come output "1", "2" e infine "0".
La funzione cerca la stringa e ritorna la posizione della prima occorrenza trovata, senza quindi tener conto di eventuali doppioni.
La quarta chiamata ad "array_search()", invece, non produce nessun output, in quanto la funzione torna il valore booleano "false" che echo non stampa.

8. Array

Gli Array sono dei contenitori di variabili.
Possono contenere ogni tipo di variabile e possono essere multidimensionali.
Ci sono vari modi di dichiarare un Array. Vediamoli assieme :

$mioArray = array(1, 22.5, "ciao");

$altroArray[0] = 1;
$altroArray[1] = 22.5;
$altroArray[2] = "ciao";

I 2 array dell'esempio, $mioArray e $altroArray sono equivalenti.
In sostanza non c'è un limite specifico di quanti valori possa contenere un Array, in quanto dipende dalla memoria che la nostra applicazione ha a disposizione.

PHP inizia a contare gli elementi da zero, di conseguenza per accedere al primo elemento di un Array, è sufficiente specificare il nome dell'array preceduto dal dollaro $, e mettere il valore zero (0) fra parentesi quadre, in questo modo :

echo $mioArray[0];

Il valore fra le parentesi quadre è detto Indice dell'array, e non è consentito avere due indici uguali nello stesso array.

L'indice serve appunto per accedere a un determinato valore dell'array, e nel caso in cui si parli di array associativo, allora l'indice non sarà un numero intero ma bensì una stringa.

Anche qui vediamo i due modi per usare un array associativo :

$array1 = array("nome" => "John", "cognome" => "Doe");

$array2["nome"] = "Mario";
$array2["cognome"] = "Rossi";

echo $array1["nome"]; // stampa : John
echo $array2["cognome"]; // stampa : Rossi

L'array associativo si usa quindi allo stesso modo di un array classico, con la differenza che l'indice, essendo una stringa, non sarà più chiamato Indice ma bensì Chiave dell'array, e per accedere ai suoi valori servirà quindi una determinata stringa.

La differenza sostanziale fra questi due tipi di array, sta nel metodo per scorrerli, dal momento che difficilmente quando useremo un array, sapremo a priori quanti valori conterrà e quali saranno esattamente gli indici o le chiavi.

Detto questo, vediamo alcune delle funzioni più importanti che PHP ci mette a disposizione per gestire gli array, e passiamole velocemente in rassegna :

  • count() - Conta i valori presenti in un array
  • array_push() - Aggiunge il valore specificato alla fine di un dato array
  • array_search() - Cerca il valore specificato in un dato array
  • list() - Assegna valori alle variabili specificate come se fossero un array
  • each() - Restituisce la corrente coppia chiave/valore e incrementa il puntatore dell'array
  • reset() - Reimposta il puntatore dell'array alla sua posizione iniziale

Vediamo ora un esempio di assegnazione e scorrimento di un array classico, mediante alcune delle funzioni sopracitate :

$mioarr = array();

array_push($mioarr, "minnie");
array_push($mioarr, "topolino");
array_push($mioarr, "pluto");

echo "L'array contiene " . count($mioarr) . " valori!\n\n"; // stampa : L'array contiene 3 valori!

for ($i = 0; $i < count($mioarr); $i++)
	echo "Il valore " . ($i + 1) . " è " . $mioarr[$i] . "!\n";

/* la FOR stamperà :
Il valore 1 è minnie!
Il valore 2 è topolino!
Il valore 3 è pluto!
*/

Al contrario, ora vedremo come scorrere un array associativo in modo ordinato. Essendo associativo non possiamo incrementare la chiave come l'indice che è un numero intero, ma dovremo servirce di alcuni funzioni di PHP.

$arr = array();
$arr["nome"] = "John";
$arr["cognome"] = "Doe";
$arr["citta"] = "Sconosciuta";
$arr["nascita"] = "01/01/1980";

while (list($chiave, $valore) = each($arr))
	echo "$chiave : $valore<br />\n";

Abbiamo usato la funzione "list()" e la "each()" ottenendo questo risultato.

La funzione list(), non è esattamente una funzione ma piuttosto un costrutto del linguaggio, che nel nostro esempio, inizializza ed assegna le variabili $chiave e $valore passategli da each().

each() la prima volta che viene chiamata, punta al primo valore dell'array e lo estrae passandolo a list().
Ogni volta che la funzione viene chiamata, ritorna il nuovo valore e incrementa di nuovo il puntatore al valore successivo, per prepararsi alla prossima chiamata. Quando l'array è finito, each() ritorna il valore false e il ciclo while si interrompe.

Per far tornare il puntatore di each() al valore iniziale in qualsiasi momento, è sufficiente chiamare la funzione reset().

Condividi contenuti