Le Matrici e la Funzione Filter

Ultima modifica: 30-05-2016

Più volte in queste pagine abbiamo scritto degli appunti sulle matrici. Ma ogni volta, come è logico, vengono presentate da un diverso punto di vista o viene presentato un modo diverso di lavorare con queste nostre grandi amiche.

Il motivo per cui io personalmente insisto sull'argomento è perchè lavorare con le matrici, anziché lavorare direttamente sui dati già memorizzati nelle celle di un foglio di Excel, specialmente se i dati sono numerosi, è da ricercare nel fatto che questa metodologia ci fa risparmiare tempo. Sembra strano in quanto, per lavorare con le matrici, dobbiamo compiere più azioni che lavorare semplicemente sui dati già residenti in celle:

mentre per lavorare sui dati già individuati nel foglio basta

Ma è così e ve lo dimostro:

per eseguire l'ordinamento di un elenco di 500 voci direttamente nelle celle, col mio computer impiego circa 19''
per memorizzare 2000 dati in una matrice, eseguirne l'ordinamento, riscrivere i dati ordinati nelle celle, ne impiego solo 2''

Per la questione sull'ordinamento vi rimando all'articolo "Ordinare i dati"esempio. Spero che abbiate un elenco o una tabella che abbia un numero considerevole di dati con cui testare la mia convinzione.


La funzione Filter

Questa volta vogliamo esaminare una funzione che, se applicata ad una matrice ad una dimensione, ci restituisce un'altra matrice, a base 0 (zero), che contiene gli elementi che contengono una sottostringa usata come stringa di ricerca.

Si tratta della funzione Filter e la sintassi è:

NuovaMatrice = Filter(sourcearray, match[, include[, compare]]).

La funzione cerca tutte le stringhe memorizzate in sourcearray e che contengono o non contengono (dipende dall'argomento include) un insieme di caratteri memorizzati nell'argomento match e le restituisce in un'altra matrice a base 0 (zero). Se in sourcearray non viene trovata alcuna corrispondenza di match, la funzione Filter restituisce una matrice vuota.

In pratica da una matrice che contiene una lista di nomi è possibile estrarre o escludere tutti i nomi che iniziano, contengono o finiscono con una determinata sequenza di caratteri.

 

Ma prima di andare avanti debbo esporre alcuni limiti che ho riscontrato:

Con match = "ri":

Il suo uso è semplice.

Dopo le operazioni preliminari per creare la matrice e stabilito cosa cercare, si può applicare la funzione alla matrice in questo modo:

ArrayResult = Filter(SourceArray, Match, False, vbTextCompare) ' per trovare gli elementi non corrispondenti

ArrayResult = Filter(SourceArray, Match, True, vbTextCompare) ' per trovare gli elementi corrispondenti oppure

ArrayResult = Filter(SourceArray, Match, , vbTextCompare) ' per trovare ancora gli elementi corrispondenti

Ma veniamo subito all'esempio pratico.

abbiamo questa tabella con un elenco di nomi il valore da cercare (in E1), ed il metodo (in E2).

L'ultima colonna viene usata per visualizzare i risultati.

        A     B     C     D     E     F     G     H  
1 Muscoline     il valore da cercare de      
2 Coccanile     il metodo true      
3 Demonte              
4 Pianezze San Lorenzo              
5 Rifreddo di Saluzzo              
6 Cittadella              
7 Uppello              
8 Malamocco              
9 Coccanile              
10 Segezia              
11 Libbiano              
12 Andrate              
13 Malborghetto              
14 Borboruso              
15 Limatola              
16 Montalbano Elicona              
17 Collinello              
18 Scerne di Pineto              
19 coccanile              
20 Trucchi              
21 Rignano sull'Arno              
22 Guagnano              
23 Coccanile              
24 Santa Caterina Villarmosa              
25 Carassai              
26 Portico              

Questo che segue è il codice che ho usato in questo esempio già ampiamente commentato per cui mi astengo dall'aggiungere altri commenti.

Sub FilterInMatrice()
'    prima parte: dichiarazione delle variabili
Dim SourceArray()
Dim NumElem, R
Dim Match, ArrayResult, Include
Dim Intervallo As Range
'    cancello il contenuto della colonna H in cui vanno mostrati i risultati
Columns("H:H").ClearContents
'    definizione dell'intervallo e della matrice da elaborare
Set Intervallo = Range("A1").CurrentRegion
For R = 1 To Intervallo.Rows.Count
    ReDim Preserve SourceArray(1 To R)
    SourceArray(R) = Intervallo(R, 1)
Next
'    lettura della stringa da cercare e del metodo da usare
Match = Range("E1") '    legge la stringa da cercare
Include = Range("E2") '    legge il metodo da usare
'    applicazione della funzione Filter alla matrice
ArrayResult = Filter(SourceArray, Match, Include, vbTextCompare)
'    visualizzazione dell'elaborato
For R = LBound(ArrayResult) To UBound(ArrayResult)
    Intervallo(R + 1, 1).Offset(0, 7) = ArrayResult(R)
Next
If UBound(ArrayResult) = -1 Then
    MsgBox "nessun elemento trovato"
End If
End Sub

Senza usare la funzione Filter al posto della semplice istruzione

ArrayResult = Filter(SourceArray, Match, Include, vbTextCompare)

dovrei organizzare un ciclo For ... Next confrontando di volta in volta la stringa da cercare contenuta in Match con la stringa che viene passata dalla matrice SourceArray durante il ciclo.

Al posto di

' .........................
ArrayResult = Filter(SourceArray, Match, Include, vbTextCompare)
' ..............................

Avremo una cosa del genere:

' ...............................
For A = LBound(SourceArray) To UBound(SourceArray)
'Così per richiamare tutti i nomi che includono la stringa contenuta in Match
If InStr(1, SourceArray(A), Match, vbTextCompare) Then
'Così per richiamare tutti i nomi che non includono la stringa contenuta in Match
'If InStr(1, SourceArray(A), Match, vbTextCompare) = 0 Then
'Così per ottenere i confronti casesensitive
'If InStr(1, SourceArray(A), Match) Then

B = B + 1
ReDim Preserve ArrayResult(B)
ArrayResult(B) = SourceArray(A)
End If
Next
' ..............................

Come potete notare la procedura è leggermente più lunga e di conseguenza la sua esecuzione, su una matrice di grosse dimensioni, rallentata.

Questo, in ogni caso sarebbe il risultato con l'esempio sviluppato con la tabella in esame.

Se in "E1" scriviamo de ed in "E2" scriviamo true nella colonna "H" otterremo: Se in "E1" lasciamo ancora la stringa de ed in "E2" scriviamo false nella colonna "H" otterremo:
Demonte
Cittadella
Muscoline
Coccanile
Pianezze San Lorenzo
Rifreddo di Saluzzo
Uppello
Malamocco
Coccanile
Segezia
Libbiano
Andrate
Malborghetto
Borboruso
Limatola
Montalbano Elicona
Collinello
Scerne di Pineto
coccanile
Trucchi
Rignano sull'Arno
Guagnano
Coccanile
Santa Caterina Villarmosa
Carassai
Portico

Bene. Anche questa è fatta. Al prossimo aggiornamento.