Il lavoro presentato negli ultimi due articoli, visto nel suo insieme, forse è stato un po' dispersivo. Nasce l'esigenza di scrivere due righe come riflessione su quello che abbiamo fatto.
Oramai penso sia consolidato il concetto della utilità, almeno in certi lavori, di lavorare con le matrici che altro non sono che delle variabili aggregate tra loro e a cui ci si può riferire facendo uso degli indici.
Anche se solo idealmente, è bene abituarci all'idea di considerare le variabili e le matrici allo stesso modo delle celle di un foglio di lavoro di Excel.
In un foglio di lavoro di Excel possiamo leggere i dati singolarmente servendoci degli appropriati indici di riga e colonna
MioDato = Cells(1, 2)
oppure in forma tabellare dando il compito di generare gli indici di riga e colonna a cicli opportunamente istruiti
For R = PrimaRiga To UltimaRiga
For C = PrimaColonna To UltimaColonna
MioDato = Cells(R, C)
Next
Next
Alla stessa maniera possiamo comportarci con le matrici.
Leggendo le istruzioni sopra riportate è lecito immaginare (dico solo immaginare) di leggere invece di Cells il nome di una matrice e che gli indirizzi di riga e colonna usati per riferirsi a specifiche locazioni del foglio siano gli indici delle due dimensioni di una matrice a cui ci riferiamo per determinare le locazioni della matrice.
Come in un foglio di Excel possiamo impostare una tabella basandoci sulle righe o sulle colonne e scegliendo la disposizione dei dati in esse, altrettanto possiamo fare con le matrici.
Ma attenzione: mentre su un foglio di Excel la scelta può essere arbitraria (disposizione di una tabella con i record lungo le righe ed i campi disposti nelle colonne o viceversa), alcune volte non può essere altrettanto arbitraria la scelta della disposizione di dati tabellari in una matrice.
Questo è il caso di una matrice dinamica a due dimensioni.
Normalmente siamo abituati a vedere un database come una serie di righe che ospitano i vari record e di colonne che accolgono i campi. Si potrebbe immaginare così una tabella in un foglio di Excel e così possiamo immaginare una tabella memorizzata in una matrice.
| Campo 1 | Campo 2 | Campo 3 | |
| Record 1 | |||
| Record 2 | |||
| Record 3 | |||
| Record 4 | |||
| Record 5 | |||
| Record 6 | |||
| Record 7 |
Questa disposizione può andare bene per una matrice, statica o dinamica che sia, che tuttavia, una volta creata, non deve essere più modificata.
Ma, se durante l'attività è necessario aggiungere o rimuovere record, questa disposizione non va più bene perchè in questi casi per ridimensionare dinamicamente la matrice senza perdita di dati dobbiamo usare la sintassi: ReDim Preserve Matrice (Indici) e l'unica dimensione che si può ridimensionare deve essere l'ultima.
L'uso della parola chiave Preserve, infatti, permette di estendere o ridurre solo l'ultima dimensione. Nell'esempio di una matrice progettata come quella rappresentata nella tabella sopra la giusta sintassi deve essere:
ReDim Preserve Matrice (1 To 7, 1 To 3 + 1)
E' ovvio che, in una matrice costruita come quella rappresentata sopra, questa istruzione effettua il ridimensionamento nella direzione dei campi, per noi inutile, anzi dannosa. Nella gestione di un database, abbiamo la necessità di ridimensionare la matrice nella direzione dei record.
Perciò è necessario progettare la matrice come mostrato nella seguente tabella:
| Record 1 | Record 2 | Record 3 | Record 4 | Record 5 | Record 6 | Record 7 | |
| Campo 1 | |||||||
| Campo 2 | |||||||
| Campo 3 |
In questo modo possiamo ridimensionare dinamicamente la matrice nella direzione dei record con ReDim Preserve:
ReDim Preserve Matrice (1 To 3, 1 To 7 + 1)
Normalmente per popolare o leggere una matrice a due dimensioni usiamo servirci di due cicli nidificati:
Un banale esempio di memorizzazione di dati in una matrice e relativa visualizzazione del suo contenuto potrebbe essere il seguente:
Nell'esempio qui sopra, prima di utilizzare la matrice determiniamo le sue dimensioni leggendo le dimensioni dell'intervallo da cui dover prelevare i dati.
Purtroppo non è sempre possibile determinare a priori la quantità di dati da dover memorizzare nella matrice.
In questi casi abbiamo la possibilità di ridimensionare dinamicamente la matrice man mano che leggiamo i dati da memorizzare.
Per questo lavoro ci viene in aiuto la parola chiave Preserve
Purtroppo c'è un limite: usando ReDim Preserve possiamo ridimensionare solo l'ultima dimensione della matrice.
Con la routine vista qui sopra abbiamo creato una matrice a due dimensioni dimensionandola in questo modo:
ReDim Matrice(1 To NumRec, 1 To NumCampi)
ossia, nella prima dimensione abbiamo i record e nella seconda i campi:
| campo 1 | Campo2 | |
|---|---|---|
| Record 1 | Giuliana | P.za della Pace, 40 |
| Record 2 | Michele | Via Tulipani, 24 |
| Record 3 | Gabriele | viale dello Splendore |
| Record 4 | Gabriele | Lungomare Rodi |
| Record 5 | Stefano | via G. Leopardi |
| Record 6 | Marcello | via Milano 13 |
| Record 7 | Giuliana | via Cona |
Per poter lavorare una matrice con la parola chiave Preserve occorre che la matrice sia creata in altra maniera, e cioè come mostrato in questa tabella:
| Record 1 | Record 2 | Record 3 | Record 4 | Record 5 | ecc | |
|---|---|---|---|---|---|---|
| campo 1 | Giuliana | Michele | Gabriele | Gabriele | Stefano | ecc |
| campo 2 | P.za della Pace, 40 | Via Tulipani, 24 | viale dello Splendore | Lungomare Rodi | via G. Leopardi | ecc |
Questo che segue è un esempio di come memorizzare i dati in una matrice che usa la parola chiave Preserve:
Come vedete i due cicli (quello esterno per i record e quello intervo per i campi) sono posti proprio come nella prima routine.
Questi sono i passaggi principali da compiere:
Ad ogni avanzamento del ciclo esterno (quello dei record) viene incrementata la seconda dimensione della matrice:
ReDim Preserve Matrice(1 To NumCampi, 1 To Record)
All'interno del secondo ciclo, quel che viene incontrato nel normale flusso dei dati di origine, viene memorizzato nella matrice in maniera inversa:
Matrice(Campi, Record) = Intervallo(Record, Campi)
Il dato trovato nella posizione RC del foglio viene memorizzato nella posizione CR della matrice:
| R | C | R | C | ||
|---|---|---|---|---|---|
| 1 | 1 | viene memorizzato in | 1 | 1 | (ovvio all'inizio) |
| 1 | 2 | viene memorizzato in | 2 | 1 | |
| 2 | 1 | viene memorizzato in | 1 | 2 | incr di riga |
| 2 | 2 | viene memorizzato in | 2 | 2 | |
| 3 | 1 | viene memorizzato in | 1 | 3 | incr di riga |
| 3 | 2 | viene memorizzato in | 2 | 3 | |
Lo stesso lavoro viene eseguito per visualizzare i dati memorizzati nella matrice.
Vengono istruiti i due cicli nidificati nell'ordine Riga Colonna e poi si esegue:
Intervallo(Record, Campi + 10) = Matrice(Campi, Record)
usando lo stesso schema di prima.
E' possibile inserire un nuovo record in mezzo alla matrice.
Abbiamo una matrice di questo tipo:
| Record 1 | Record 2 | Record 3 | Record 4 | Record 5 | Record 6 | Record 7 | Record 8 | |
| Campo 1 | ||||||||
| Campo 2 | ||||||||
| Campo 3 |
Vogliamo inserire un nuovo record nella quarta posizione:
Per consentire alla matrice di ospitarfe un nuovo record incrementiamo la sua seconda dimensione con un:
NumRec = UBound(Matrice, 2) + 1
ReDim Preserve Matrice(1 To NumCampi, 1 To NumRec)
| Record 1 | Record 2 | Record 3 | Record 4 | Record 5 | Record 6 | Record 7 | Record 8 | Nuovo spazio | |
| Campo 1 | |||||||||
| Campo 2 | |||||||||
| Campo 3 |
Spostiamo verso il basso tutti i record a cominciare dal n° 8 fino ad arrivare al n° 4. In questo caso è necessario procedere dal basso iniziando dal penultimo record perchè altrimenti l'operazione sarebbe molto più complessa, se non impossibile.
For Record = NumRec - 1 To 4 Step -1
For Campi = 1 To NumCampi
Matrice(Campi, Record + 1) = Matrice(Campi, Record)
Next
Next
Fatto questo ci ritroviamo in questa situazione con il record n° 4 duplicato:
| Record 1 | Record 2 | Record 3 | Record 4 | Record 4 | Record 5 | Record 6 | Record 7 | Record 8 | |
| Campo 1 | |||||||||
| Campo 2 | |||||||||
| Campo 3 |
Fatto questo vengono sostituiti i contenuti del record n° 4 aggiungendo quelli nuovi
For Campi = 1 To NumCampi
Matrice(Campi, 4) = "quel che vuoi"
Next
ottenendo finalmente la matrice opportunamente ridimensionata e coi nuovi dati inseriti:
| Record 1 | Record 2 | Record 3 | Record 4 | Record 5 | Record 6 | Record 7 | Record 8 | Record 9 | |
| Campo 1 | |||||||||
| Campo 2 | |||||||||
| Campo 3 |
Questa è senz'altro la più semplice tra le operazioni da compiere su una matrice.
Stabilito quale è il record da modificare lo si sovrascrive semplicemente:
RecordDaModificare = 7
For Campi = 1 To NumCampi
Matrice(Campi, RecordDaModificare) = "quel che vuoi"
Next
La procedura è simile a quella già vista per l'inserimento di un record in mezzo alla matrice, solo che ora, invece di aggiungere un record, lo dobbiamo eliminare.
Si procede in questo modo:
Si individua il record da eliminare:
RecordDaEliminare = 2
Quindi, partendo da questo record fino al penultimo, si spostano in sù tutti i record sottostanti:
For Record = RecordDaEliminare To NumRec - 1
For Campi = 1 To NumCampi
Matrice(Campi, Record) = Matrice(Campi, Record + 1)
Next
Next
Si toglie una unità al numero totale dei record:
NumRec = UBound(Matrice, 2) - 1
e si ridimensiona la matrice. Questa operazione fa perdere l'ultimo record che risulta il doppione del penultimo grazie agli spostamenti effettuati.