VBA: come saltare in modo condizionale un'iterazione del ciclo for


101

Ho un ciclo for su un array. Quello che voglio fare è testare una certa condizione nel ciclo e passare alla successiva iterazione se vera:

For i = LBound(Schedule, 1) To UBound(Schedule, 1)
    If (Schedule(i, 1) < ReferenceDate) Then
        PrevCouponIndex = i
        Continue   '*** THIS LINE DOESN'T COMPILE, nor does "Next"
    End If
    DF = Application.Run("SomeFunction"....)
    PV = PV + (DF * Coupon / CouponFrequency)
Next

So che posso fare:

 If (Schedule(i, 1) < ReferenceDate) Then Continue For

ma voglio essere in grado di registrare l'ultimo valore di i nella variabile PrevCouponIndex.

Qualche idea?

Grazie


3
Hai detto: "So di poterlo fare: If (Schedule(i, 1) < ReferenceDate) Then Continue For" Ne sei sicuro? Continuenon è una parola chiave VBA.
mwolfe02

@ mwolfe02 - no non sono sicuro, ma ho visto esempi da qualche parte (cpearson?)
Richard H

potrebbe essere stato un esempio VB.NET
Tipo anonimo

Risposte:


31

Non potresti semplicemente fare qualcosa di semplice come questo?

For i = LBound(Schedule, 1) To UBound(Schedule, 1)
  If (Schedule(i, 1) < ReferenceDate) Then
     PrevCouponIndex = i
  Else
     DF = Application.Run("SomeFunction"....)
     PV = PV + (DF * Coupon / CouponFrequency)
  End If
Next

4
In effetti, è esattamente quello che ho fatto :) Ma ancora mi infastidisce devo avvolgere le cose nel pezzo Else. Grazie
Richard H

4
+1 @RichardH beh, devi usare un IFper il test, quindi non è così costoso a livello di codice. Tuttavia, dovresti assicurarti che il risultato più comune Schedule(i, 1)sia inferiore ReferenceDatea evitare di eseguire il Elsepiù spesso del necessario. Altrimenti usa (ReferenceDate>=Schedule(i, 1)). (se il test è 50/50, non è necessaria l'ottimizzazione)
brettdj

Potrebbe diventare un po 'complicato con numerosi if nidificati ... se ad esempio è necessario controllare un bel po' di Application.Match risultati all'interno di ogni iterazione per non trovare una corrispondenza prima di utilizzare i risultati. Ma così sia, ci sono cose peggiori nella vita!
JeopardyTempest

183

VBA non ha una Continueo qualsiasi altra parola chiave equivalente per passare immediatamente all'iterazione del ciclo successivo. Suggerirei un uso giudizioso di Gotocome soluzione alternativa, soprattutto se questo è solo un esempio artificioso e il tuo codice reale è più complicato:

For i = LBound(Schedule, 1) To UBound(Schedule, 1)
    If (Schedule(i, 1) < ReferenceDate) Then
        PrevCouponIndex = i
        Goto NextIteration
    End If
    DF = Application.Run("SomeFunction"....)
    PV = PV + (DF * Coupon / CouponFrequency)
    '....'
    'a whole bunch of other code you are not showing us'
    '....'
    NextIteration:
Next

Se questo è davvero tutto il tuo codice, però, @Brian è assolutamente corretto. ElseMetti semplicemente una clausola nella tua Ifdichiarazione e finiscila.


18
Grazie, questo è un buon suggerimento per GoTo (VBA - teletrasportarti indietro al 1964)
Richard H

3
@George: GoTo può essere oggetto di abusi (motivo per cui ho qualificato la mia affermazione; vedi giudizioso ), ma non è intrinsecamente malvagio. Seriamente, però, è impossibile scrivere un VBA robusto senza l'istruzione Goto semplicemente perché ne hai bisogno per la gestione degli errori (cioè On Error Goto).
mwolfe02

3
@ George: Quello che sto raccomandando qui è una soluzione alternativa per un'altra limitazione del linguaggio (nessuna Continuedichiarazione). Si può sostenere che l'uso di Continuein altre lingue dovrebbe essere evitato e quindi dovrebbe essere evitato anche qui. In qualche modo, il link che hai postato fa il mio punto. Il collegamento è alla GoTodichiarazione in VB.Net. VB.Net ha sia la gestione degli errori strutturata che le istruzioni Continue For/ Continue Do. Non c'è davvero bisogno di GoToVB.Net; Sospetto che sia stato lasciato in posizione in gran parte per supportare una conversione più semplice del codice VBA / VB6 esistente.
mwolfe02

4
@George GoToha il vantaggio di ridurre la nidificazione. Saltare un'iterazione del ciclo senza aggiungere un livello di rientro è, IMO, uno dei pochi usi legittimi di GoToVBA / VB6. Soprattutto se estrai il corpo del loop nella sua procedura .
Mathieu Guindon

4
@George ho visto annidamenti che non violano il codice , ma distruggono il cervello ;)
Mathieu Guindon

35

Puoi usare una sorta di continueusando un annidato Do ... Loop While False:

'This sample will output 1 and 3 only

Dim i As Integer

For i = 1 To 3: Do

    If i = 2 Then Exit Do 'Exit Do is the Continue

    Debug.Print i

Loop While False: Next i

1
interessante ..meglio che usare goto!
ozmike

È fantastico
Kubie

1
Questa dovrebbe essere la risposta
Stian Ulriksen

Molto elegante e simpatico
Alexis Sánchez Tello

5
Intelligente! Mi dispiacerebbe essere il ragazzo che si imbatte in questo senza commenti però. lol
Caltor

14

Continue For non è valido in VBA o VB6.

Da questa pagina MSDN sembra che sia stato introdotto in VB.Net in VS 2005./Net 2.

Come hanno già detto gli altri, non c'è davvero un'opzione diversa da usare Gotoo un file Else.


2

Ciao anch'io sto affrontando questo problema e lo risolvo usando il codice di esempio sotto

For j = 1 To MyTemplte.Sheets.Count

       If MyTemplte.Sheets(j).Visible = 0 Then
           GoTo DoNothing        
       End If 


'process for this for loop
DoNothing:

Next j 

Non sono sicuro del motivo per cui questo è stato votato negativamente e la risposta successiva ha oltre 100 voti positivi, e sono la stessa risposta!
rryanp

4
Probabilmente perché questa risposta è stata scritta 5 anni dopo quella risposta, ed è esattamente lo stesso concetto. Perché dovrebbe ricevere voti positivi?
Tyler StandishMan

-2

Forse prova a mettere tutto alla fine se e usa un altro per saltare il codice questo farà in modo che tu non sia in grado di usare il GoTo.

                        If 6 - ((Int_height(Int_Column - 1) - 1) + Int_direction(e, 1)) = 7 Or (Int_Column - 1) + Int_direction(e, 0) = -1 Or (Int_Column - 1) + Int_direction(e, 0) = 7 Then
                Else
                    If Grid((Int_Column - 1) + Int_direction(e, 0), 6 - ((Int_height(Int_Column - 1) - 1) + Int_direction(e, 1))) = "_" Then
                        Console.ReadLine()
                    End If
                End If
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.