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.