Triplo Ciclo For .. Next

I cicli  For ... Next sono legati al concetto di insiemi. Questi insiemi possono essere oggetti di vario tipo : controlli, barre di comando, celle del foglio di lavoro, fogli di lavoro, ma anche matrici, valori, ecc. ecc. Quando si deve eseguire una verifica o una ricerca su ogni componente di un insieme, come per esempio cercare un valore in una serie di celle (Range), allora e utile ricorrere proprio alla struttura di un ciclo For ... Next.

Sono due tra le strutture cicliche di controllo (ne esistono altre) :

  • un ciclo che cercherà PER OGNI componente dell'insieme, usando la forma For Each <elemento> di un <insieme> ... Next <passa all'elemento successivo>. un esempio

Per ogni cella (C)<elemento>  nell'<insieme> Range("A1:A20"). In questo caso viene assegnato un indice implicito rappresentato dal numero di celle presenti nel Range A1:A20, indice che identifica numericamente le 20 celle. L'istruzione Next, posta alla fine del ciclo, non fa altro che passare all'indice successivo, ripetendo le istruzioni, fino a che non ha raggiunto l'indice 20, dopodichè esce dal ciclo.

For Each C in Range("A1:A20")

...istruzioni

Next

  • oppure un ciclo, posto un valore iniziale ed un valore finale, che si baserà su un contatore (indice non implicito) che si incrementerà di una unità ad ogni Next fino a raggiungere il valore finale, usando la forma For I <I è il contatore>= 1 To 20 ... Next <passa al valore successivo rappresentato da I>. Un esempio

Questa forma consente di "spazzolare" un intervallo di <elementi> di un <insieme>, dichiarando noi l'indice per quanti <elementi> (1 To 20 ) dovrà essere ripetuto il ciclo (20 volte) ed identificando l'<elemento> con il contatore (o indice). Rifacendoci all'esempio sopra, dove si scorre la colonna A fino alla cella 20, identificate come <insieme> dall'oggetto Range, in questo caso useremo Cells come <elemento> dell'oggetto Foglio (in questo caso l'<insieme>). Visto che per identificare le celle del foglio di lavoro, usiamo due indici, il primo è sempre l'indice di riga, il secondo è sempre l'indice di colonna (es.: Cells(1, 3) = C1), useremo al posto dell'indice di riga il numero rappresentato dal contatore ( I ) per scorrere tutte le righe fino alla 20.

For I = 1 To 20

Cells(I, 1) seguono istruzioni

Next

I è una variabile che può essere identificata con qualsiasi lettera o nome, N oppure X o ancora Cont, o quel che vi pare, l'importante che poi usiate quello che avrete scelto come contatore al posto dell'indice riga, oppure assegnare il tipo di variabile con Dim, es.:

Dim Cont as Integer

For Cont = 1 To 20

Cells(Cont, 1) seguono istruzioni

Next

Fatte queste premesse, passo ad illustrare un esempio scaturito da una richiesta, strettamente legato a cicli For.. Next, e lo propongo in due varianti.

Vediamo il problema:

In una tabella, formata da 10 colonne e da 10 righe, si trovano dei numeri, da 1 a 100. Si voleva che, cancellando uno qualsiasi dei numeri rimasti, i numeri successivi a quello cancellato, scalassero di una cella, e si ripristinasse la progressione dei i numeri rimasti, lasciando quindi vuota l'ultima cella. Vediamo le tabelle: nella prima è stato eliminato il valore nella cella evidenziata in giallo; come si nota, manca il numero 64

Si vuole quindi che a partire dal 65, si scali di una cella, ricreando la naturale progressione, e questo sarà il risultato finale, in cui i numeri sono in progressione ed è l'ultima cella a restare vuota.:

Vediamo come procedere:

  • abbiamo bisogno di un ciclo che controlli tutte le celle di una stessa riga della tabella, e quindi lavori avanzando colonna dopo colonna.

  • abbiamo bisogno di un secondo ciclo, che una volta completato il ciclo per le colonne della prima riga, passi alla riga successiva dell'elenco per ripetere il ciclo sulle colonne, e che questo ciclo scorra fino alla fine tutte le righe.

Visto che stiamo cercando se una cella sarà vuota, inseriremo un controllo If .. Then. Se troveremo una cella vuota, e quì ho scelto la soluzione più veloce, cancello l'intera tabella, assegno alla prima cella (A1) il valore 1, e rigenero l'intera sequenza dei numeri fermandomi a 99, con un terzo ciclo For.. Next, dopodichè esco da tutti i cicli con Exit For (ripetuto due volte perchè due sono i cicli "esterni" inizializzati.). Se invece non verrà trovata nessuna cella vuota, il terzo ciclo (interno) non si verifica e si uscirà dalla routine quando tutte le celle sono state controllate. Questa la routine:
 

Sub Riordina()

'istruzione necessaria per non vedere lo scorrere dei cicli
Application.ScreenUpdating = False

'assegnazione alla variabile "zona" del range su cui operare
Set zona = Range("A1:J10")

'inizio del primo ciclo esterno, che inizializza l'indice riga (rwIndex); cioè a partire dalla 'riga 1 (e poi fino alla riga 10)
For rwIndex = 1 To 10

'inizia il secondo ciclo, che nella riga ora selezionata (la 1) scorre tutte le colonne, 'dall'indice colonna 1 fino alla 10 (colIndex)
For colIndex = 1 To 10

'con l'<insieme> Foglio1, per l'<elemento> Cella (indice riga, indicecolonna)(questi indici 'rappresentati ora da rwIndex e da colIndex)
With Worksheets("Foglio1").Cells(rwIndex, colIndex)

'se la cella è vuota, allora
If .Value = "" Then

'cancelliamo tutta l'area assegnata a "zona"
zona.ClearContents

'assegnamo alla prima cella dell'area "zona" (A1) il valore 1

zona.Cells(1) = 1

'inizio del terzo ciclo, partendo dalla cella 2 (la cella uno è già stata inizializzata con 1) e 'fino al valore rappresentato dal numero di celle (zona.Cells.Count= 100) - 1 perchè 'dovrà mancare una cella, l'ultima

For I = 2 To zona.Cells.Count - 1
'I ora è un contatore, e determina su quale cella della "zona" si interviene, sommando al 'valore della cella precedente (la I -1) la cella attuale, una unità (1)
zona.Cells(I) = zona.Cells(I - 1) + 1
Next I

'finito con Next I il terzo ciclo che ha poste nelle celle la progressione dei numeri fino a 99, si esce dai due cicli precedenti aperti, e si salta a End Sub
Exit For: Exit For
End If
End With
Next colIndex
Next rwIndex

End Sub

Ho preparato anche la routine per riempire tutta la tabella con numeri da 1 a 100, ripristinando la tabella completa: Questa la routine, inutili mi pare, i commenti:

Sub Riempi()
Application.ScreenUpdating = False
Set zona = Range("A1:J10")
zona.ClearContents
For I = 2 To zona.Cells.Count
zona.Cells(1) = 1
zona.Cells(I) = zona.Cells(I - 1) + 1
Next
End Sub

Questa invece la seconda variante, promessa all'inizio. Presupponendo che si voglia il comportamento relativo al problema (quello di scalare celle e ripristino della progressione) MA il tutto su una tabella dove il numero di celle vuote sia superiore ad 1, e dove quindi è necessario "contare" quante celle vuote si trovano per determinare quante celle vuote lasciare alla fine.

Come procedere:

  • dovremo usare i due cicli For..Next per scorrere tutte le righe e tutte le colonne, per cercare quante celle vuote sono presenti.

  • ci affideremo ad un contatore (cont) che memorizzi quante celle vuote sono presenti con

  • If .Value = "" Then
    cont = cont + 1
    End If

  • Alla fine dei due cicli di ricerca, controlleremo se il valore del contatore è maggiore di 0 (zero), in caso sia maggiore, iniziamo il ciclo di azzeramento tabella, riassegnazione alla prima cella del valore 1, ed incremento delle altre celle di una unità in progressione, ottenendo dove fermarci dal valore ottenuto dal conteggio di quante celle ci sono nella tabella, meno il valore rappresentato dal contatore.

Sub Riordina()
Application.ScreenUpdating = False
Set zona = Range("A1:J10")
For rwIndex = 1 To 10
For colIndex = 1 To 10
With Worksheets("Foglio1").Cells(rwIndex, colIndex)
If .Value = "" Then
cont = cont + 1
End If
End With
Next colIndex
Next rwIndex


If cont > 0 Then
zona.ClearContents
For I = 2 To zona.Cells.Count - cont
zona.Cells(1) = 1
zona.Cells(I) = zona.Cells(I - 1) + 1
Next
End If
End Sub

 

Buon lavoro.


prelevato sul sito http://ennius.interfree.it