Domanda
Ho bisogno di poter estrarre da una frase inserita in una cella, l'elenco di tutte le parole contenute con a fianco scritto il numero di volte che ogni parola è ripetuta, e magari in ordine decrescente.
Faccio un esempio che forse è più facile farmi capire:
"non ci si mangia tra un cane ed un altro cane"
Dovrei ottenere qualcosa del genere:
| un | 2 |
| cane | 2 |
| si | 1 |
| mangia | 1 |
| tra | 1 |
| non | 1 |
| ci | 1 |
| ed | 1 |
| altro | 1 |
Risposta
Io risolverei la questione col metodo dei dati univoci
già presentato tra queste pagine.
Per raggiungere lo scopo io seguirei questi passi:
leggo la frase dalla cella
la divido usando la funzione Split col carattere separatore spazio (" ") (questa operazione mi mette tutte le parole in una matrice)
inizio la raccolta dei dati univoci usando una Collection (come visto nel già
citato articolo)
durante la raccolta dei dati univoci controllo lo stato dell'errore
se l'errore è diverso da 0 (zero) incremento il contatore (se c'è un errore in questa procedura è perchè la Collection contiene già l'elemento che si sta aggiungendo)
se non c'è errore
viene incrementata una matrice a due dimensioni
nella prima dimensione viene memorizzata la parola trovata
nella seconda dimensione viene posto il contatore (il numero 1)
terminata questa operazione si ordina la matrice
alla fine viene scritto il contenuto della matrice nell'intervallo desiderato
Questa che segue è la routine completa
Sub ContaParoleOrdinato()
Dim Elenco As New Collection
Dim R, R1, Contatore
Dim Frase As String
Dim Parole As Variant
Dim Lista()
Frase = Range("A1")
Parole = Split(Frase, " ")
On Error Resume Next
For R = LBound(Parole) To UBound(Parole)
Elenco.Add Parole(R), CStr(Parole(R))
If Err <> 0 Then
For R1 = 1 To Elenco.Count
If LCase(Elenco(R1)) = LCase(Parole(R)) Then
Lista(2, R1) = Lista(2, R1) + 1
End If
Next
Err = 0
Else
Contatore = Contatore + 1
ReDim Preserve Lista(1 To 2, 1 To Contatore)
Lista(1, Contatore) = Parole(R)
Lista(2, Contatore) = 1
End If
Next
On Error GoTo 0
For R = 1 To UBound(Lista, 2) - 1
For R1 = R + 1 To UBound(Lista, 2)
If Lista(2, R) < Lista(2, R1) Then
Var1 = Lista(1, R)
Lista(1, R) = Lista(1, R1)
Lista(1, R1) = Var1
Var1 = Lista(2, R)
Lista(2, R) = Lista(2, R1)
Lista(2, R1) = Var1
End If
Next
Next
For R = 1 To UBound(Lista, 2)
Cells(R, 5) = Lista(1, R)
Cells(R, 6) = Lista(2, R)
Next
End Sub
Cerchiamo di esaminare alcuni passaggi del codice che potrebbero restare oscuri.
Prima parte : acquisizione dei dati
Parole = Split(Frase, " ")
separa tutte le parole contenute in Frase usando il carattere separatore spazio
Seconda parte: rielvamento dati
il dato è già stato acquisito
If Err <> 0 Then
se è stato sollevato l'errore lo determiniamo leggendo il valore della variabile di sistema Err: in questo caso la parola è stata già inserita nella Collection, quindi occorre incrementarne il conteggio
in questo caso dobbiamo trovare la sua posiazione nella Collection per incrementarne l'occorrenza; questo lavoro viene eseguito dal seguente ciclo:
For R1 = 1 To Elenco.Count
If LCase(Elenco(R1)) = LCase(Parole(R)) Then
Lista(2, R1) = Lista(2, R1) + 1
End If
Next
Err = 0
in questo ciclo notiamo
LCase(Elenco(R1)) = LCase(Parole(R))
si usa la funzione LCase per rendere il confronto non sensibile alle maiuscole e minuscole
Lista(2, R1) = Lista(2, R1) + 1
Lista() è una matrice a due dimensioni: nella prima dimensione abbiamo memorizzato la parola trovata e nella seconda dimensione le sue occorrenze; con questa istruzione viene incrementata di una unità le occorrenze della parola nella frase.
il dato è appena acquisito
Fin qui se viene sollevato un errore per il tentativo di duplicare un elemento nella Collection. Ma se l'errore non viene sollevato l'elemento viene aggiunto con successo nella Collection. In questo caso entriamo nella porzione Else del costrutto If ... End If
Contatore = Contatore + 1
ReDim Preserve Lista(1 To 2, 1 To Contatore)
Lista(1, Contatore) = Parole(R)
Lista(2, Contatore) = 1
viene incrementata la seconda dimensione della matrice
Lista(1, Contatore) = Parole(R)
nella prima dimensione della matrice viene aggiunto l'elemento corrente appena accettato dalla Collection:
Lista(2, Contatore) = 1
nella seconda dimensione della matrice viene memorizzato il numero 1 che rappresenta la prima occorrenza dell'elemento appena aggiunto
Terza parte: ordinamento dei dati in base alle loro occorrenze
Se vogliamo che il nostro elaborato venga visualizzato in ordine crescente o decrescente dobbiamo affidarci ad uno degli algoritmi di ordinamento di cui possiamo disporre. Se i dati sono pochi possiamo affidarci senz'altro al Bubble Sort.
Il bubble sort (letteralmente: ordinamento a bolle) è un semplice algoritmo di ordinamento particolarmente indicato per l'ordinamento di array. Non si tratta di un algoritmo particolarmente efficiente. Tuttavia è piuttosto noto e utilizzato (sia in ambito didattico che da parte di programmatori professionisti) in virtù della sua semplicità. Come tutti gli algoritmi di ordinamento, può essere usato per ordinare dati di un qualsiasi tipo. Il nome dell'algoritmo è dovuto al fatto che, durante l'applicazione del procedimento, i valori vengono spostati all'interno dell'array con una dinamica che ricorda il movimento delle bollicine in un bicchiere di champagne.
L'ordinamento a bolle o bubble sort consiste nel raggiungere l'ordinamento attraverso il confronto del primo elemento con tutti i rimanenti (N-1 elementi), eseguendo i dovuti scambi e ripetendo l'operazione per tutti i restanti N-1 elementi. In tal modo l'elemento più piccolo (o più grande, a seconda del tipo di ordinamento che vogliamo: ascendende o discendente) viene a galla come una bolla (da cui il nome di ordinamento a bolle) e quindi a trovarsi in cima all'elenco.
Queste sono le istruzioni usate per l'ordinamento:
For R = 1 To UBound(Lista, 2) - 1
For R1 = R + 1 To UBound(Lista, 2)
If Lista(2, R) < Lista(2, R1) Then
Var1 = Lista(1, R)
Lista(1, R) = Lista(1, R1)
Lista(1, R1) = Var1
Var1 = Lista(2, R)
Lista(2, R) = Lista(2, R1)
Lista(2, R1) = Var1
End If
Next
Next
Come si può desumere dal listato del programma, il bubble sort consiste essenzialmente in due cicli for nidificati con un test (l'istruzione if) per confrontare due elementi.
In questo caso vogliamo che il valore più grande salga in cima alla lista ed è per questo che eseguiamo il confronto con:
If Lista(2, R) < Lista(2, R1) Then
Questo è tutto. Spero di essere stato chiaro. In caso contrario sono qui.
Mike