Azioni ambivalenti: matrici o intervalli

 

Fin qui, finora, abbiamo lavorato o sulle celle del foglio di calcolo o sulle matrici.

Questa volta vorrei soffermarmi per approfondire una questione che potrà farci vedere un modo diverso di lavorare sia con l'uno che con l'altro metodo: ossia cerchiamo di vedere se e come è possibile istruire azioni che possano andare bene per entrambe le metodologie.

 

Questa è una visualizzazione schematica di un foglio di lavoro: Questa invece lo schema di una matrice
            A           B           C           D           E     
1          
2          
3          
4          
5          
  Campo1 Campo2 Campo3 Campo4 Campo5
Rec1          
Rec2          
Rec3          
Rec4          
Rec5          

Lavorando con le celle possiamo far in modo di riferirci alle celle con gli indici, per le righe e le colonne, che iniziano da 1.

Lavorando con le matrici ci accorgiamo che gli indici, se non diversamente dichiarati, possono iniziare anche da 0 (zero).

Vediamo come possiamo organizzarci.

Per creare delle routines che vadano bene sia per gli intervalli di un foglio di Excel sia per le matrici, occorre seguire delle piccole procedure.

Per creare una Matrice o un Intervallo:

Per conoscere l'indice superiore di questi due oggetti:

Per conoscere l'indice inferiore di questi due oggetti:

Per leggere o scrivere un valore contenuto in una determinata locazione di un intervallo o di una matrice:

C'è una lieve differenza per trattare delle locazioni che sono al di fuori della dimensione massima di un Intervallo o di una Matrice.

  1. Per un intervallo possiamo leggere o scrivere dei valori in tutte le locazioni disponibili nel foglio, anche se l'intervallo di partenza è una singola cella
  2. Per una matrice queste operazioni sono consentite solo nei limiti definiti nel loro dimensionamento.
    Per le matrici tuttavia:
    • se si tratta di una matrice Statica i limiti sono quelli dichiarati nel loro primo dimensionamento e non possiamo in nessun caso superarli:
      Dim MiaMatrice(1 To 20, 1 To 7)
    • se si tratta di una matrice Dinamica è possibile aumentare le sue dimensioni in due modi:
      • con perdita dei dati: ReDim Mia_Matrice(1 To Nr, 1 To Nc), ed in questto caso possiamo aumentare a nostro piacimento qualsiasi dimensione
      • senza perdita di dati: ReDim Preserve matrice(1 To Nr, 1 To Nc + 4)
        in questo secondo caso è possibile aumentare dinamicamente solo la seconda dimensione

 

Fatte queste premesse possiamo provare con una piccolo applicativo.

Cercare la prima occorrenza di un valore

Per poter scrivere del codice che vada bene sia per una matrice che per un intervallo la cosa migliore è creare una funzione che possa essere semplicemente copiata ed incollata in qualsiasi file di Excel.

Immaginiamo di avere una tabella del genere:

 

Nome Indirizzo
Giuliana P.za della Pace, 40
Michele Via Tulipani, 24
Gabriele viale dello Splendore
Gabriele Lungomare Rodi
Stefano via G. Leopardi
Marcello via Milano 13
Giuliana via Cona
Maria via C. Battisti
Edith via Rossini
Alessandra via Marconi
Gabriele Via P. Montesi, 52
Maria Via P. Montesi, 88
Stefano via Fermi
Alessandra via S. Maria dell’Arco
Michele Cologna
Stefania Via P. Montesi, 52
Michele Via Pietro Montesi, 52
Maria P.za della Pace, 40
Francesco Via Tulipani, 24

e che in essa vogliamo cercare un nome.

La funzione

Function MiaTabellaSta(Cosa, Elenco) As String
Dim RMax, CMax, rMin, cmin, R, C
If IsObject(Elenco) Then
RMax = Elenco.Rows.Count
rMin = 1
CMax = Elenco.Columns.Count
cmin = 1
Else
RMax = UBound(Elenco, 1)
rMin = LBound(Elenco, 1)
CMax = UBound(Elenco, 2)
cmin = LBound(Elenco, 2)
End If
For R = rMin To RMax
For C = cmin To CMax
If LCase(Cosa) = LCase(Elenco(R, C)) Then
MiaTabellaSta = CStr(R) & "*" & CStr(C)
Exit Function
End If
Next
Next
MiaTabellaSta = ""
End Function

In questa funzione:

come prima cosa occorre stabilire se l'elenco (Elenco) che gli abbiamo mandato è un oggetto (Intervallo di celle) o una matrice

Fatto questo possiamo scrivere la funzione che ci serve. In questo caso la funzione cerca un determinato valore che dovrebbe essere nell'elenco.

Le eventuali routines che possono usare questa funzione

Trova Valore In Intervallo

Sub TrovaValoreInIntervallo()
Dim Intervallo As Range
Dim NR, NC, Mess
Dim Valore As String, Localizzato As String
Dim Coord
Worksheets("Foglio1").Select
Set Intervallo = Range("A1").CurrentRegion
NR = Intervallo.Rows.Count - 1
NC = Intervallo.Columns.Count
Set Intervallo = Intervallo.Offset(1, 0).Resize(NR, NC)
Valore = InputBox("Dimmi un nome da cercare")
Localizzato = MiaTabellaSta(Valore, Intervallo)
Mess = "Quel che cerchi "
If Localizzato <> "" Then
Coord = Split(Localizzato, "*")
Mess = Mess & "ha l'indice in riga " & Coord(0) & " col " & Coord(1) & "dell'intervallo"
Else
Mess = Mess & "NON ci sta..."
End If
MsgBox Mess
End Sub

In questa routine, dopo aver definito l'intervallo da usare per la ricerca (primo settore):

Trova Valore In Matrice

Sub TrovaValoreInMatrice()
Dim Intervallo As Range
Dim NR, NC, R, C, Mess
Dim Valore As String, Localizzato As String
Dim Coord
Worksheets("Foglio1").Select
Set Intervallo = Range("A1").CurrentRegion
NR = Intervallo.Rows.Count - 1
NC = Intervallo.Columns.Count
Set Intervallo = Intervallo.Offset(1, 0).Resize(NR, NC)
ReDim Matrice(1 To NR, 1 To NC)
For R = 1 To NR
For C = 1 To NC
Matrice(R, C) = Intervallo(R, C)
Next
Next
Valore = InputBox("Dimmi un nome da cercare")
Localizzato = MiaTabellaSta(Valore, Matrice)
Mess = "Quel che cerchi "
If Localizzato <> "" Then
Coord = Split(Localizzato, "*")
Mess = Mess & "ha l'indice in riga " & Coord(0) & " col " & Coord(1) & "della matrice"
Else
Mess = Mess & "NON ci sta..."
End If
MsgBox Mess
End Sub

Identico lavoro per questa routine, ma, prima di andare alla funzione, viene creata la matrice raccigliendo i dati dal foglio.

 

Trova Valore In Dati esterni

Sub TrovaValoreEsterno()
Dim Valore As String, Localizzato As String
Dim NomeFile, FileNum
Dim R, C, MatriceTemp(), MiaMatrice(), Mess, Coord
Dim Test, RMax, CMax
Worksheets("Foglio1").Select
NomeFile = ActiveWorkbook.Path & "\database.txt"
If Dir(NomeFile) = "" Then
MsgBox "impossibile trovarfe il file"
Exit Sub
End If
Close
FileNum = FreeFile
Open NomeFile For Input As #FileNum
R = 0
Do While Not EOF(FileNum)
R = R + 1
ReDim Preserve MatriceTemp(1 To R)
Line Input #FileNum, MatriceTemp(R)
Loop
Close #FileNum
Test = Split(MatriceTemp(1), "|")
RMax = UBound(MatriceTemp)
CMax = UBound(Test)
ReDim MiaMatrice(1 To RMax, 0 To CMax)
For R = 1 To RMax
Test = Split(MatriceTemp(R), "|")
For C = LBound(Test) To UBound(Test)
MiaMatrice(R, C) = Test(C)
Next
Next
Valore = InputBox("Dimmi un nome da cercare")
Localizzato = MiaTabellaSta(Valore, MiaMatrice)
Mess = "Quel che cerchi "
If Localizzato <> "" Then
Coord = Split(Localizzato, "*")
Mess = Mess & "ha l'indice in riga " & Coord(0) & " col " & Coord(1) & " della matrice"
Else
Mess = Mess & "NON ci sta..."
End If
MsgBox Mess
End Sub

In questa ultima routine ho usato questo file di testo esempio :

 

Considerazioni finali:

Con questa prospettiva potremmo risparmiare molto tempo per la creazione di codice scritto ad hoc e, soprattutto avremo meno confusione se dobbiamo trattare intervalli o celle dalle tipologie più varie.

 

Buon lavoro