Ordinamento delle matrici in base a più campi

 

Il problema

Sul problema delle matrici abbiamo già parlato abbondantemente, ma ci sono certi argomenti un po' difficili da essere compresi, per cui, anche se precedentemente ne abbiamo già parlato, ci torniamo su guardando il problema da un altro punto di vista.

Stiamo parlando dell'ordinamento di una matrice basato su un campo e dell'ordinamento di una matrice su più campi.. E' ovvio che la matrice di cui stiamo parlando è a 2 dimensioni: una per record ed una per campi.

 

Per Ordinamento di una matrice basato su un campo intendiamo dire che, data una matrice i cui campi sono: nome, cognome, CAP, città, prov, via, possiamo decidere di ordinare i dati contenuti nella matrice in base al Nome, o al Cognome, ecc.

Per Ordinamento di una matrice basato su più campi intendiamo dire che la stessa matrice possiamo ordinarla prima per un campo, poi per un secondo campo, quindi per un terzo campo e così via.

 

Nell'immagine che osserviamo qui sotto vediamo due tabelle: una a destra e l'altra a sinistra.

La tabella su cui lavoriamo sarà quella di destra. La tabella di sinistra ci servirà soltanto per controllare le modifiche avvenute nella matrice dopo i due ordinamenti effettuati ed esternate nella tabella di destra e servirà poi per essere trasferita così com'è nella zona di destra per un ulteriore test.

 

 

Soluzione

Qui di seguito vengono esposte le due procedure per ottenere l'uno o l'altro tipo di ordinamento.

Per l'ordinamento ho usato il classico, in entrambi i casi, l'algoritmo basato su Bubble Sort (ordinamento a bolle), anche se tra tutti gli algoritmi è il più lento, perchè tra tutti è quello di più semplice comprensione.

Le due routine le scriviamo nel Primo Modulo standard

 

Ordinamento di una matrice in base ad un unico campo

Questa sarà la InputBox dalla quale verrà effettuata la scelta del campo da ordinare:

In questa routine (la routine Sub OrdinaMatrice() ) ci comportiamo in questa maniera:

  1. vengono memorizzati nella matrice i dati contenuti nella seconda tabella (quella di destra)

  2. si chiede quale deve essere la colonna da ordinare e la colonna scelta verrà memorizzata nella variabile Campo che indicherà quale sarà il campo da ordinare

  3. si procede con l'ordinamento secondo il metodo Bubble Sort

  4. vengono confrontati i dati residenti nella colonna precedentemente indicata

  5. se il confronto risulta positivo (If Matr(R, Campo) > Matr(R1, Campo) Then)

  6. si procede allo scambio dei due record coinvolti scambiando tra loro tramite un ciclo un campo alla volta

    For C = 1 To NCamp
    VarTemp = Matr(R, C)
    Matr(R, C) = Matr(R1, C)
    Matr(R1, C) = VarTemp
    Next

 

Fatto questo la missione è compiuta e l'istruzione successiva è solo una dimostrazione di come si trovano i dati nella matrice ordinata


Ordinamento di una matrice in base a più campi

Questa sarà la UserForm dalla quale si sceglieranno i campi e l'ordine con cui questi saranno ordinati:

Lievemente più complessa è la seconda routine (Sub OrdinaMatrice2() ). Nella routine che effettua l'ordinamento su più campi la procedura è quasi la stessa anche se, inizialmente, meno intuitiva.

  1. vengono memorizzati nella matrice i dati contenuti nella seconda tabella (quella di destra)

  2. tramite una UserForm vengono scelti i campi e l'ordine con cui la matrice dovrà essere ordinata; infatti i campi possono essere presi con un ordine qualsiasi

  3. all'uscita dalla UserForm si raccolgono in una matrice gli indici delle ComboBox da cui si è effettuata la scelta ( ICampi(R) = Controls("ComboBox" & C1).ListIndex + 1) che si riferiscono alle colonne dei vari campi

  4. si torna con questa seconda matrice nella procedura che elabora la matrice

  5. a questo punto se la matrice è vuota non succede nulla, ma se la matrice contiene 1 o più elementi si effettua l'ordinamento

  6. l'algoritmo che viene eseguito dalle istruzioni successive si basa sul confronto non più tra i singolo dati contenuti nella matrice ma sul confronto delle stringhe che si sono create con

    For CRec = 1 To CampiRec 'sono i campi scelti per l'ordinamento
    Nome1 = Nome1 & Matr(R, ICampi(CRec))
    Nome2 = Nome2 & Matr(R1, ICampi(CRec))
    Next

    tenendo presente che in ICampi(CRec) ci sono le coordinate dei campi scelti e nell'ordine scelto nella UserForm

  7. il successivo confronto non sarà fatta direttamente sui dati residenti nella matrice ma su una stringa che contiene più dati raccolti dalla matrice nell'ordine precedentemente scelto:

    CarloBoscatiNapoli e CarloBoscatiMilano

    oppure

    VerezzoBoscatiAndrea e NapoliZazzeraCarlo

  8. lo scambio successivo avviene secondo la solita maniera

    For C = 1 To NCamp
    VarTemp = Matr(R, C)
    Matr(R, C) = Matr(R1, C)
    Matr(R1, C) = VarTemp
    Next

Anche qui l'azione si conclude con la visualizzazione del contenuto della matrice ordinata

Trasferimento del contenuto della matrice sul foglio di Excel

Degna di attenzione è il metodo usato per trasferire la matrice in un intervallo del foglio di Excel:
Tabella.Offset(0, 8) = Matr

dove Tabella.Offset(0, 8) è un Range, spostato di 8 colonne rispetto all'intervallo chiamato "Tabella", di uguale dimensione della matrice.

Se l'intervallo di destinazione dovesse rivelarsi di proporzioni inferiori a quelle della matrice i dati della matrice non verrebbero semplicemente visualizzati

Se l'intervallo di destinazione dovesse rivelarsi di proporzioni superiori a quelle della matrice nelle celle eccedenti verrebbe visualizzato
il messaggio #ND

 

 


Alcune note esplicative sul codice relativo all'ordinamento

Vorrei ora mettere a confronto le istruzioni principali usate per i due tipi di ordinamento.

 
Metodo BubbleSort

Il cuore dell'ordinamento in base ad un campo sta in queste istruzioni:

For R = 1 To NRec - 1
For R1 = R + 1 To NRec
If Matr(R, Campo) > Matr(R1, Campo) Then
For C = 1 To NCamp
    VarTemp = Matr(R, C)
    Matr(R, C) = Matr(R1, C)
    Matr(R1, C) = VarTemp
Next
End If
Next
Next

 

La routine per l'ordinamento basato su più campi usa queste istruzioni:

For R = 1 To NRec - 1
For R1 = R + 1 To NRec
Nome1 = "": Nome2 = ""
For CRec = 1 To CampiRec

'ora i valori dei campi sono concatenati nell'ordine scelto precedentemente nella UserForm

Nome1 = Nome1 & Matr(R, ICampi(CRec))
Nome2 = Nome2 & Matr(R1, ICampi(CRec))
Next
If Nome1 > Nome2 Then
For C = 1 To NCamp
    VarTemp = Matr(R, C)
    Matr(R, C) = Matr(R1, C)
    Matr(R1, C) = VarTemp
Next
End If
Next
Next

 

 

Prima osservazione: nello schema di sinistra, ordinamento in base ad un campo, vengono confrontati i valori contenuti nella matrice, mentre nello schema di destra, ordinamento basato su più campi, prima di eseguire il confronto viene eseguito un concatenamento di tutti i valori contenuti nei campi precedentemente indicati e selezionati nella UserForm

 

Seconda osservazione: in entrambi i casi, lo scambio che si andrà ad effettuare avverrà con queste modalità:

 

si pone in una variabile temporanea il contenuto della locazione puntata da R e C

si copia nella locazione puntata da R(iga) e C(olonna) il contenuto della locazione puntata da R1 e C

si copia nella locazione puntata da R1 e C il contenuto precedentemente salvato nella variabile temporanea

For C = 1 To NCamp
VarTemp = Matr(R, C)
Matr(R, C) = Matr(R1, C)
Matr(R1, C) = VarTemp
Next

 

 

E' ovvio che nel modulo che contiene le istruzioni appena esaminate, circondate ed evidenziate da una serie di asterischi, è stato necessario aggiungere altro codice per memorizzare i dati nella matrice e per la scelta del campo o dei campi da ordinare. Per il commento a queste istruzioni aggiuntive si rimanda agli articoli già apparsi nel sito o, se proprio necessario, sarà fatto in un altro momento.

 

Conclusioni

Allego il file che ho usato per testare ed eseguire gli ordinamenti nella matrice. Il file liberamente scaricabile e consultabile è ordinamento in base a piu campi.zip (22KB).

 

Buon lavoro

 

prelevato sul sito www.ennius.altervista.org