Chi ha a che fare con elenchi di qualsiasi genere prima o poi s'imbatte nella necessità di ordinare alfabeticamente o numericamente i propri dati.
Spesso è sufficiente la funzione di Excel:
Range(Cells(1, 2), Cells(NumMax, 2)).Sort Key1:=Range("B1"), _
order1:=xlAscending, _
Header:=xlGuess, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
se si desidera un ordinamento discendente, anziché ascendente si può sostituire order1:=xlAscending con order1:=xlDescending che tra l'altro è abbastanza veloce, ma non abbastanza, secondo me.
A volte per motivi che non sto ad elencare perché sono innumerevoli, possiamo desiderare di costruirci o usare tecniche personalizzate per eseguire certi tipi di ordinamento
ne cito solo alcuni:
E' qui che cominciano i guai: infatti spesso ci accorgiamo di dover lottare con un fattore molto fastidioso: il tempo.
Nel mio posto di lavoro, essendo, tra l'altro, responsabile dell'archivio, spesso ho a che fare con un numero elevato di cartelle da ordinare numericamente e deporre negli scaffali.
Il lavoro è lungo e noioso per cui ho il tempo di pensare. Il metodo che uso (manualmente, naturalmente, perché diversamente non si può fare) non è simile a quello famosissimo del Bubble-sort, che per molto tempo ho usato nelle mie applicazioni già dai tempi del Commodore, ma un altro non documentato nelle varie guide.
Le tecniche di ordinamento sono tante ma quella presentata più frequentemente in qualche manuale è la tecnica del Bubble-sort che di solito è la più facile da gestire e da capire. Il nome Bubble-sort è dovuto al fatto che gli elementi da ordinare si muovono lentamente verso l'alto (come bolle) fino a raggiungere la loro posizione definitiva nell'elenco ordinato.
Allora mi sono messo ad analizzare le azioni che compivo e, notando che sono decisamente migliori del Bubble-sort, mi è nata l'idea di creare una sorta di metodo personale da applicare ai dati da ordinare.
Mi sono messo all'opera, ho confrontato i due metodi e, visto che quello mio, specialmente con un numero elevato di elementi da ordinare, è notevolmente migliore di quello classico, è nata quella che sto per presentare.
Questo è il famoso Bubble-sort eseguito sui valori presenti nelle celle del foglio:
For I = 1 To NumMax - 1
For A = I + 1 To NumMax
If Cells(A, 1) > Cells(I, 1) Then
Numero = Cells(I, 1)
Cells(I, 1) = Cells(A, 1)
Cells(A, 1) = Numero
End If
Next
Next
Con questo metodo (il Bubble-sort):
Questo è il metodo da me elaborato in seguito alla mia esperienza lavorativa:
For I = 2 To NumMax
If Cells(I, 1) > Cells(I - 1, 1) Then
A = 1
Do Until Cells(I, 1) > Cells(A, 1)
A = A + 1
Loop
Fine = A
Numero = Cells(I, 1)
For A = I To Fine + 1 Step -1
Cells(A, 1) = Cells(A - 1, 1)
Next
Cells(Fine, 1) = Numero
End If
Next
La differenza tra le due routines sta in questo:
Entrambi i metodi sopra esposti operano l'ordinamento in senso decrescente (dal più grande al più piccolo). Se volessimo un tipo di ordinamento inverso (dal più piccolo al più grande) basta semplicemente invertire l'operatore di confronto sopra usato da > (maggiore) a < (minore).
Esempio: dove leggiamo:
If Numero > Cells(I - 1, 1) Then
basta scrivere:
If Numero < Cells(I - 1, 1) Then
Fin qui le considerazioni che abbiamo fatto sui due metodi di ordinamento.
Siccome parliamo di economia di tempo è d'obbligo a questo punto un'altra considerazione:
è più conveniente lavorare direttamente sulle celle o su variabili?
Se i dati sono pochi (alcune decine, forse anche alcune centinaia, di elementi da ordinare) è ovvio che qualsiasi metodo va bene.
Ho svolto delle indagini e confortato dall'esito delle mie prove e da ciò che si legge in alcuni manuali, sono giunto a questa conclusione:
ove possibile è preferibile lavorare con le variabili. Ma se i dati da elaborare sono molti, dove troviamo tutte le variabili necessarie e quanti nomi di variabili dobbiamo tenere a mente?
In questo caso la prima cosa utile che ci viene in mente sono le matrici.
Siccome in questa sede, per non annoiare ulteriormente chi mi legge, non parlerò delle tecniche dell'uso delle matrici, se di queste tecniche qualcuno dovesse aver bisogno, vi rimando agli articoli specifici.
L'uso di questo mezzo che il linguaggio di programmazione ci offre ci permetterà di raggiungere il nostro scopo.
Innanzitutto per usare una matrice dobbiamo inizializzarla e, a seconda i casi possiamo fare uso di una matrice statica o una matrice dinamica.
Se facciamo uso di una matrice statica è sufficiente un banale Dim Matrice(1 To 100) o quello che vogliamo.
Se facciamo uso di una matrice dinamica iniziamo con Dim Matrice() (o qualsiasi nome vogliamo)
quindi contiamo il numero di elementi che vogliamo mettere nella matrice con uno dei metodi più appropriati come per esempio questo:
NumMax= Range(Range("B1"), Range("B1").End(xlDown)).Count
una volta ottenuto il numero di elementi da mettere nella matrice diamo alla nostra matrice la giusta dimensione con:
ReDim Matrice(1 To NumMax)
a questo punto siamo pronti a riempire la nostra matrice.
Ecco quindi l'inizio della routine per copiare il contenuto delle celle nella matrice:
Dim Matrice()
' seguono altre eventuali dichiarazioni di variabili
NumMax= Range(Range("B1"), Range("B1").End(xlDown)).Count
ReDim Matrice(1 To NumMax)
For I = 1 To NumMax
Matrice(I) = Cells(I, 2)
Next
A questo punto siamo pronti per lavorare con la nostra matrice.
Vediamo perciò di adattare una delle due routines appena esposte alle nostre necessità. Prendiamo come esempio la seconda delle due esposte (che poi è, in ogni caso, quella che a questo punto propongo) e, tanto per testare i tempi di esecuzione, la applichiamo prima all'elenco residente sul foglio, poi alla matrice.
| il metodo applicato direttamente sul foglio | il metodo applicato ad una matrice |
|---|---|
| raccolta dei dati nella matrice | |
For I = 1 To NumMax Matrice(I) = Cells(I, 2) Next |
|
For I = 2 To NumMax If Cells(I, 1) > Cells(I - 1, 1) Then A = 1 Do Until Cells(I, 1) > Cells(A, 1) A = A + 1 Loop Fine = A Numero = Cells(I, 1) For A = I To Fine + 1 Step -1 Cells(A, 1) = Cells(A - 1, 1) Next Cells(Fine, 1) = Numero End If Next |
For I = 2 To NumMax If Matrice(I) > Matrice(I - 1) Then A = 1 Do Until Matrice(I) > Matrice(A) A = A + 1 Loop Fine = A Numero = Matrice(I) For A = I To Fine + 1 Step -1 Matrice(A) = Matrice(A - 1) Next Matrice(Fine) = Numero End If Next |
| trascrizione dei dati ordinati sul foglio | |
For I = 1 To NumMax Cells(I, 6) = Matrice(I) Next |
Come spesso dico in queste circostanze, se i dati sono pochi, la scelta di uno o dell'altro metodo è ininfluente, quindi ognuno potrà lavorare come più gli aggrada. Ma se il numero dei dati da elaborare sono nell'ordine di alcune migliaia io insisto sempre nell'affermare che lavorare con le matrici fa risparmiare molto tempo prezioso.
Se quel che è stato detto fin qui è chiaro si può continuare con la lettura del seguente paragrafo, altrimenti consiglio di rileggere ancora quanto fin qui è stato scritto perché le cose si potrebbero complicare alquanto.
Punto primo
Non è più sufficiente creare una matrice ad una sola dimensione, ma ne dobbiamo creare una Matrice a più dimensioni e ci comportiamo così:
Dim Matrice()
' seguono altre eventuali dichiarazioni di variabili
NumMax= Range(Range("B1"), Range("B1").End(xlDown)).Count
ReDim Matrice(1 To NumMax, 1 To 4)
For I = 1 To NumMax
Matrice(I,1) = Cells(I + 1, 1)
Matrice(I,2) = Cells(I + 1, 2)
Matrice(I,3) = Cells(I + 1, 3)
Matrice(I,4) = Cells(I + 1, 4)
Next
Perché quel Cells(I + 1, 1)? Ma semplice. Perché se abbiamo un elenco a più colonne, senz'altro avremmo anche delle intestazioni di colonna e non vogliamo inserire nella matrice anche le intestazioni di colonna.
Punto secondo
alcune modifiche le dobbiamo apportare anche nella routine di ordinamento:
For I = 2 To NumMax
If Matrice(I,1) > Matrice(I - 1,1) Then ' se non è l'elemento che sta nella prima colonna
' a dover essere ordinato invece di 1 indicheremo il numero della colonna interessata
' all'ordinamento
A = 1
Do Until Matrice(I,1) > Matrice(A,1) ' stessa nota anche in questa istruzione
A = A + 1
Loop
Fine = A
A1 = Matrice(I, 1) ' poniamo in variabili temporali tutto il contenuto della riga
A2 = Matrice(I, 2) ' puntata dal contatore del ciclo I
A3 = Matrice(I, 3)
A4 = Matrice(I, 4)
For A = I To Fine + 1 Step -1
Matrice(A, 1) = Matrice(A - 1, 1) ' spostiamo in basso tutto il contenuto
Matrice(A, 2) = Matrice(A - 1, 2) ' delle righe puntate dal ciclo A
Matrice(A, 3) = Matrice(A - 1, 3)
Matrice(A, 4) = Matrice(A - 1, 4)
Next
Matrice(Fine, 1) = A1 ' mettiamo nella riga puntata dalla variabile Fine il contenuto
Matrice(Fine, 2) = A2 ' delle variabili temporali
Matrice(Fine, 3) = A3
Matrice(Fine, 4) = A4
End If
Next
'Modifichiamo anche le istruzioni che vanno a scrivere sul foglio:
For I = 1 To NumMax
Cells(I + 1, 6) = Matrice(I, 1) ' ci ricordiamo del motivo di quel I + 1?
Cells(I + 1, 7) = Matrice(I, 2)
Cells(I + 1, 8) = Matrice(I, 3)
Cells(I + 1, 9) = Matrice(I, 4)
Next
Come conclusione ho da fare una semplice annotazione: se l'ordinamento deve essere eseguito su un numero esiguo di elementi un metodo vale l'altro e potremo scegliere quello che più ci aggrada. Ma se dobbiamo agire su un numero consistente di elementi è meglio ponderare bene la cosa e scegliere il metodo più idoneo.
Dopo questa chiacchierata il mio file di Esempio è quasi d'obbligo, ma con esso anche alcune note su come leggerlo; per l'uso penso non ci siano problemi: è sufficiente premere i pulsanti che ho sistemato nei vari fogli.
Spero che queste semplici spiegazioni siano sufficienti a spiegare lo spirito del file che offro alla vostra sperimentazione.
Il file da scaricare:
(ordinamento.zip) (30KB)