Istruzioni For...Next (ciclo), For Each..Next - dal 04/09/04 pagina vista: volte

Con questo articolo provo a fornire una spiegazione più semplicistica dei concetti legati ai cicli.

Questa istruzione For..Next, definita "ciclo", serve a ripetere una serie di istruzioni un certo numero di volte. Esistono più tipi di cicli, ma sono tutti "strumenti" utilizzabili per ripetere determinate istruzioni un certo numero di volte. Tra tutti gli strumenti disponibili in programmazione, il ciclo For..Next è sicuramente il più semplice da capire. Intanto vediamo come si scrive: usiamo degli indici riga per capire meglio

10: For nome variabile = numero iniziale To numero finale - Con For indichiamo quante volte dovranno essere ripetute  le istruzioni contenute nella riga 20 attraverso il numero rappresentato da nome variabile

20: istruzioni di cosa fare (nome variabile)

30: Next incrementa il numero iniziale di una unità fino a raggiungere il numero finale; quindi Next (che in italiano vuol dire successivo) provvede a rimandare l'esecuzione del codice alla riga 20 tante volte quanto dichiarato con For. Perchè si possa memorizzare il numero di quante volte è stata eseguita l'istruzione della riga 20, si usa nome variabile come un contatore che all'inizio del ciclo avrà il valore del numero iniziale e si incrementerà di uno ad ogni Next fino a che, raggiunto il valore del numero finale si uscirà dal ciclo di istruzioni.

Vediamo ora di comporre un esempio che visualizzi meglio la sintassi appena usata: usiamo la lettera "r" come nome variabile (sarà il nostro contatore, che inizierà da 1 (numero iniziale) e tramite Next, si incrementerà di 1 fino a raggiungere il limite massimo rappresentato da 10 (numero finale). Come nome variabile potremo usare ciò che vorremo. una lettera o più lettere, una parola, ecc., spesso visto che la variabile rappresenta un numero intero, si usa la lettera "i" che starebbe per Integer (numero intero) o anche per N che starebbe per Number (numero), io ho usato la "r" in quanto mi riferirò nell'esempio alle righe ed "r" è l'iniziale)

10: For r = 1 To 10

20: valore = Cells(r, 1).Value

30: MsgBox valore

40: Next

Cosa abbiamo fatto ? Abbiamo creato un ciclo che si ripeterà 10 volte ( 1 To 10 ), poi abbiamo usato un'altra variabile: valore, (stesso discorso per il nome usato, poteva essere X, andava bene lo stesso), la quale ci restituirà, ad ogni ciclo, il contenuto (Value) di una cella, e ce lo mostrerà tramite una finestra di messaggio (MsgBox). E' evidente che non ci interessa vedere il messaggio della stessa cella per 10 volte, ma vorremo scorrere 10 celle (Cells), e vedere quindi il contenuto di ognuna delle 10 celle. Poichè per identificare le celle, dobbiamo usare la sintassi Cells(numeroriga, numero colonna), useremo al posto di numeroriga la variabile "r", che sarà inizialmente uguale al numero iniziale del ciclo For, quindi uno (in questo esempio), e che tramite Next si incrementerà di una unità, indicando in successione riga 2, riga 3, ecc. fino alla riga 10, mostrando il contenuto delle celle "spazzolate". Non mi sembra difficile da capire, che ne dite?

Senza accorgercene abbiamo realizzato un ciclo di ricerca dei valori contenuti in un intervallo di celle, o Range di celle. In pratica stiamo usando un ciclo che potremo sfruttare per cercare un dato. Potremo quindi ampliare a nostro piacere l'intervallo di celle da controllare, modificando il numero iniziale ed il numero finale da assegnare a For. Se volessimo ad esempio scorrere tutte le celle della colonna C (la numero 3) e iniziare dalla riga 7 fino alla 200, dovremo quindi impostare questa istruzione:

10: For r = 7 To 200

20: valore = Cells(r, 3).Value

Ma spesso in un ciclo di ricerca, vogliamo trovare un determinato valore (che potrà essere un numero, testo, data, orario), ed uscire dal ciclo senza necessariamente scorrere tutte le celle. In questo caso dovremo costruire una condizione di confronto, usando If..Then..End If, e sfruttando l'istruzione Exit For per uscire anzitempo dal ciclo. Supponiamo quindi di voler cercare la cella contenente la parola "Pippo" e di volerci fermare a quella cella; le nostre istruzioni saranno quindi.

10: For r = 7 To 200

20: valore = Cells(r, 3).Value

30: If valore = "Pippo" Then

40: Cells(r, 3).Select

50: Exit For

60: End If

70: Next

La sequenza delle istruzioni deve rispettare questo esempio: in pratica si dice, a parte l'indicazione con For di quante volte ripetere la ricerca, (cioè di quante righe scorrere). Se (If) il valore della cella in quel momento "visitata" è uguale a "Pippo", allora (Then) seleziona la cella (Select), ed esci dal ciclo (Exit For = esci dal ciclo For)), indi si chiude la condizione con End If.

Come abbiamo visto, è necessario sempre definire in un ciclo For, sia il numero iniziale sia il numero finale, o anche detti: limite inferiore, limite superiore. Nel caso però di aree delle quali non è possibile stabilire a priori l'ampiezza, per definire i due valori da assegnare al ciclo For, dovremo contare quante righe (o colonne) compongono l'area. Supponendo quindi di voler contare tutte le righe occupate nella colonna A (la 1), potremo avvalerci della funzione End per reperire l'ultima cella occupata nella colonna, partendo dalla prima cella occupata, e quindi contare le righe con Rows.Count. Useremo una variabile per memorizzare questo numero, e nel ciclo For impiegheremo la variabile al posto del numero finale. Vediamo come:

10: Set area = Worksheets(1).Range(Cells(1, 1), Cells(1, 1).End(xlDown))
20: n = area.Rows.Count
30: For r = 1 To n

Al di là del metodo che useremo per reperire l'ultima cella occupata (riga 10), impostiamo (Set)  una variabile (area) che rappresenta tutta la zona che partendo dalla cella A1, cercherà la fine (End verso il basso (xlDown)), poi ne contiamo le righe occupate assegnando il valore alla variabile "n": questo rappresenterà il limite superiore del ciclo For.

Sarà poi l'esperienza e le prove che faremo le migliori maestre per imparare ad usare i cicli, ho sempre sostenuto che nessuno nasce professore, ma è necessario applicarsi per poter imparare, ed usare il ragionamento per assimilare un concetto, insieme alla memoria.

E' possibile usare più cicli For..Next nelle nostre procedure, in particolare i "cicli annidati", cioè più cicli uno all'interno dell'altro. Questi cicli ci consento, una volta avviato il primo ciclo (esterno), di poter eseguire altri cicli (interni) per eseguire le nostre istruzioni. Seguendo gli esempi usati, vediamo come impostare una procedura a due cicli.

Supponiamo di voler cercare un dato non solo nelle righe di una colonna, ma anche nelle righe di tutte le colonne che formeranno una nostra ipotetica area dati. Avremo quindi bisogno di un ciclo che si occupi di scorre le righe, più un'altro che scorra le colonne in modo da spazzolare tutte le celle dell'area. Compreso come lavora un ciclo For..Next, risulta semplice capire che tutti i cicli impiegati avranno bisogno ognuno dei numeri iniziali e dei numeri finali , ed ogni ciclo è indipendente dall'altro per quanto riguarda il numero dei cicli.

La sintassi dell'istruzione a due cicli prevede che si inizializzino uno di seguito all'altro (tranne istruzioni condizionali eventualmente inserite tra un ciclo e l'altro, che condizionino appunto l'inizio del secondo ciclo, o altre ancora, ma non facciamo i complicati). Nell'esempio che seguiamo, vogliamo scorrere righe e colonne, ma potremo decidere se scorrere le colonne, e all'interno della colonna, scorrere le righe. Sembra lo stesso, ma in realtà cambia la direzione ed il senso di scorrimento, ed è il posizionamento del ciclo esterno che determina il senso di scorrimento e direzione. Saranno le nostre necessità che ci faranno optare con quale ciclo iniziare.

Vediamo di capire le differenze con questo esempio: ovviamente usiamo due variabili: la "r" che si riferisce alle righe, e la "c" con cui ci riferiamo alle colonne: il ciclo esterno serve a scorrere le righe, il secondo serve a scorrere le colonne: la cosa funziona così:

inizia il ciclo per scorrere le righe, e saremo alla riga 1, prima di trovare l'istruzione Next r che ci farebbe passare alla riga 2,  troviamo il secondo ciclo che ci farà scorrere le colonne dalla 1 alla 8, e solo quando sarà finito questo ciclo (con Next c) , troveremo Next r . In pratica, con le istruzioni così impostate, iniziamo a scorrere la prima riga, quindi scorriamo tutte le colonne, poi si passa alla seconda riga, ripetiamo lo scorrimento di tutte le colonne, poi si passa alla terza riga e così via fino alla fine delle righe previste dal ciclo esterno.

10: For r = 1 To 10                   

20: For c = 1 To 8

30: valore = Cells(r, c).Value

40: MsgBox valore

50: Next c

60: Next r

Se invece volessimo fare il contrario, cioè iniziare a scorrere le colonne, e per ogni colonna scorrere tutte le righe prima di passare alla seconda colonna e così via, dovremmo iniziare le istruzioni con:

10: For c = 1 To 8

20: For r = 1 To 10

Capito l'arcano? Spererei proprio di si, perchè non so fare ad usare termini più semplici. Anche per i doppi cicli, potremo reperire i numeri di quante righe e quante colonne formano la nostra area dati: con Rows.Count per contare le righe, e Columns.Count per contare le colonne, impostando due variabili, ad esempio in questo modo:

10: Set areavert = Worksheets(1).Range(Cells(1, 1), Cells(1, 1).End(xlDown))
20: n = areavert.Rows.Count
30: Set areaoriz = Worksheets(1).Range(Cells(1, 1), Cells(1, 1).End(xlToRight))
40: z = areaoriz.Columns.Count
50: For r = 1 To n
60: For c = 1 To z

Avremo quindi che "n" sarà uguale al numero di righe, e "z" sarà uguale al numero di colonne, ed assegneremo queste due variabili come limite superiore ai due cicli For Next. Da notare che per contare le colonne, usiamo End ma con la direzione verso destra (xlToRight).

 

Ciclo For Each...Next.

Il ciclo For Each...Next è simile al ciclo For...Next, ma esegue il blocco di istruzioni per ogni elemento di un insieme invece che per un numero di volte specificato.

L'esempio dei doppi cicli appena visto, per scorrere righe e colonne, e se preferite, colonne e righe, quindi tutta un'area dati, può essere sostituito dal ciclo For Each... Next, che tradotto in pellegrinese, vuol dire:

Per Ogni [elemento] [dove ?] ..istruzioni di cosa fare.. passa al successivo [elemento]

In questa istruzione non avremo bisogno di indicare il numero iniziale ed il numero finale visti con gli altri cicli per impostare quante volte ripetere le nostre istruzioni, ma saranno rappresentati da quante volte l'[elemento] sarà presente in [dove ?(cioè l'insieme)], e l'inizio sarà sempre dal primo [elemento] contenuto in [dove ?]

Che cosa significa elemento e dove ? : facendo seguito agli esempi finora seguiti, di un'area (o se preferite: tabella) in cui vogliamo trovare un dato,  elemento rappresenta una cella contenente il dato, e dove ? rappresenta l'area che contiene le celle. Useremo delle variabili per identificare l'elemento "cella" e l'"area" dove?, dimensionando la variabile cella come Range o Object, e impostando con i riferimenti della zona, l'area in cui cercare prima di iniziare il ciclo. Esempio:

10: Dim MiaCella As Object

20: Set Area = Worksheets("Fogliotuo").Range("A2:G50")

30: For Each MiaCella in Area

40: ..istruzioni di cosa fare..

50: Next

Cosa abbiamo fatto?: abbiamo dimensionato (Dim) la variabile MiaCella come oggetto (Object), poi abbiamo settato la variabile Area che sarà uguale all'intervallo che va dalla cella A2 alla cella G50 del foglio in cui vogliamo eseguire il ciclo. In pratica abbiamo impostato il numero iniziale rappresentato dalla prima cella di Area, cioè A2 ed il numero finale rappresentato dall'ultima cella di Area, cioè G50. Ora il ciclo sa da dove partire e quando terminare, infatti l'istruzione alla riga 30: dice : per ogni cella contenuta in Area, esegui le istruzioni passando dopo la prima cella alla successiva tramite Next, ripetendo le istruzioni, e così via fino all'ultima cella e quindi termina il ciclo.

Va detto che in un ciclo For Each Next lo spazzolamento delle celle avviene dalla prima cella all'ultima cella della prima riga, quindi dalla A2 alla G2, poi passa alla riga successiva cioè dalla A3 alla G3, proseguendo in questo senso sulle righe successive.

Anche con un ciclo For Each Next potremo ricorrere a vari sistemi per reperire la zona da impostare come Area, come pure usare Exit For per uscire dal ciclo nel caso di una condizione di ricerca.

Considerazioni: tutti i cicli basati su For Next e For Each Next, se usati per rintracciare un valore, troveranno tutte le celle contenenti i valori uguali al criterio di ricerca, MA si fermeranno sempre all'ultimo trovato. Oppure inseriamo istruzioni che fermino il ciclo alla cella contenente il dato cercato con oggetto.Select, per poi continuare cercando ancora. Dipenderà dalle necessità operative il tipo di istruzioni da inserire. Mentre diversa risulta l'impostazione per quei cicli che mirino per esempio alla variazione di una condizione che interessi tutte le celle di un'area che corrispondano ad un criterio. L'esempio che segue serve a colorare la cella di rosso, in tutte le celle contenenti una formula:

10: Dim MiaCella As Object

20: Set Area = Worksheets("Fogliotuo").Range("A2:G50")

30: For Each MiaCella in Area

40: If MiaCella.HasFormula = True Then

50: MiaCella.Interior.Colorindex = 3

60: End If

70: Next

Possiamo concludere questa breve panoramica con una considerazione: i cicli sono strumenti idonei per essere utilizzati con tutti gli "Insiemi" (in inglese: Collection) di "Oggetti": senza approfondire l'argomento Collection, possiamo comunque esemplificare dicendo che sono "Insiemi" :

  • le celle di un foglio di lavoro (Cells)

  • le righe e le colonne di un foglio di lavoro

  • i fogli di lavoro di una cartella di lavoro (WorkSheets)

  • gli oggetti inseribili nei fogli o nei progetti (CommandButton, TextBox, CommandBar, UserForm, ecc. ecc. ecc.)

  • le cartelle di lavoro (Workbooks)

  • i files (Workbooks) all'interno di una Directory

  • ecc. ecc.

Tutti gli "oggetti" di un "insieme" (quindi appartenenti alla stessa "Classe") possiedono un numero indice che li identifica all'interno dello stesso "insieme", se noi ad esempio usiamo per identificare una Cella (facente parte del'"insieme" di tutte le celle di un foglio di lavoro) un numero, così: Cells(10).Select vedremmo selezionata la cella J10, con Cells(261) vedremmo selezionata la cella E2, e così via. Esistono 256 celle (quindi colonne) per ogni riga, e ci sono 65536 righe, per un totale, per ogni foglio di lavoro, di 16.777.216 celle. Provate queste semplici istruzioni:

  • [A1] = Rows(1).Cells.Count - in A1 otterrete il numero di celle della riga 1 (come vedete si fa uso dell'indice di Riga (Rows(1)) per definire la riga 1 dell'"insieme" Rows (Righe)) = 256.

  • [A1] = Rows.Cells.Count - in A1 otterrete il totale di tutte le celle di tutto l'"insieme" Rows (senza numero indice) che sarà =  16.777.216 - cioè 256 celle per 65536 righe. (se usate i tasti CTRL + frecce, vi precipiterete ai quattro estremi del foglio)

Spero che queste spiegazioni possano servire a capire meglio anche tutti gli altri esempi  basati sui cicli che trovate sui due siti.

Buon lavoro.

prelevato sul sito www.ennius.altervista.org