VBA - Comment sauter conditionnellement une itération de boucle for

101

J'ai une boucle for sur un tableau. Ce que je veux faire, c'est tester une certaine condition dans la boucle et passer à l'itération suivante si c'est vrai:

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

Je sais que je peux faire:

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

mais je veux pouvoir enregistrer la dernière valeur de i dans la variable PrevCouponIndex.

Des idées?

Merci

Richard H
la source
3
Vous avez dit: "Je sais que je peux faire: If (Schedule(i, 1) < ReferenceDate) Then Continue For" En êtes-vous sûr? Continuen'est pas un mot clé VBA.
mwolfe02
@ mwolfe02 - pas sûr, mais vu des exemples quelque part (cpearson?)
Richard H
peut avoir été un exemple VB.NET
Type anonyme

Réponses:

31

Tu ne pourrais pas faire quelque chose de simple comme ça?

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
Brian
la source
4
En effet, c'est exactement ce que j'ai fait :) Mais ça me dérange quand même je dois emballer des choses dans le morceau Else. Merci
Richard H
4
+1 @RichardH et bien, vous devez utiliser un IFpour le test, donc ce n'est pas si cher que cela. Vous devez cependant vous assurer que le résultat le plus courant Schedule(i, 1)est moins que ReferenceDatepour éviter d'exécuter le Elseplus souvent que nécessaire. Sinon, utilisez (ReferenceDate>=Schedule(i, 1)). (si le test est 50/50, pas besoin d'optimisation)
brettdj
Cela pourrait devenir un peu compliqué avec de nombreux if imbriqués ... si, par exemple, vous devez vérifier plusieurs résultats Application.Match à chaque itération pour ne pas trouver de correspondance avant d'utiliser les résultats. Mais tant pis, il y a des choses pires dans la vie!
JeopardyTempest
183

VBA n'a pas de Continuemot clé ou tout autre mot clé équivalent pour passer immédiatement à l'itération de boucle suivante. Je suggérerais une utilisation judicieuse de Gotocomme solution de contournement, surtout s'il ne s'agit que d'un exemple artificiel et que votre vrai code est plus compliqué:

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

Si c'est vraiment tout votre code, cependant, @Brian est absolument correct. Mettez simplement une Elseclause dans votre Ifdéclaration et en avez terminé.

mwolfe02
la source
18
Merci, c'est un bon conseil concernant le GoTo (VBA - vous ramène à 1964)
Richard H
3
@George: GoTo peut être abusé (c'est pourquoi j'ai nuancé ma déclaration; voir judicieux ), mais ce n'est pas intrinsèquement mauvais. Sérieusement, il est impossible d'écrire un VBA robuste sans l'instruction Goto simplement parce que vous en avez besoin pour la gestion des erreurs (c'est-à-dire On Error Goto).
mwolfe02
3
@George: Ce que je recommande ici, c'est une solution de contournement pour une autre limitation de la langue (pas de Continuedéclaration). On peut soutenir que l'utilisation de Continuedans d'autres langues devrait être évitée et donc devrait être évitée ici également. À certains égards, le lien que vous avez publié fait valoir mon point de vue. Le lien est vers la GoTodéclaration dans VB.Net. VB.Net a à la fois une gestion des erreurs structurée et des instructions Continue For/ Continue Do. Il n'y a vraiment aucun besoin de GoTodans VB.Net; Je soupçonne qu'il a été laissé en place en grande partie pour prendre en charge une conversion plus facile du code VBA / VB6 existant.
mwolfe02
4
@George GoToa l'avantage de réduire l'imbrication. Sauter une itération de boucle sans ajouter un niveau d'indentation est, IMO, l'une des rares utilisations légitimes de GoToVBA / VB6. Surtout si vous extrayez le corps de la boucle dans sa propre procédure .
Mathieu Guindon
4
@George J'ai vu une nidification qui ne casse pas le code , mais détruit le cerveau ;)
Mathieu Guindon
35

Vous pouvez utiliser une sorte de continueen utilisant un imbriqué 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
Exception non-gérée
la source
1
intéressant .. mieux que d'utiliser goto!
ozmike
C'est génial
Kubie
1
Cela devrait être la réponse
Stian Ulriksen
Très élégant et agréable
Alexis Sánchez Tello
5
Intelligent! Je détesterais être le gars qui découvre cela sans commentaires. lol
Caltor
14

Continue For n'est pas valide en VBA ou VB6.

À partir de cette page MSDN, il semble avoir été introduit dans VB.Net dans VS 2005./Net 2.

Comme les autres l'ont dit, il n'y a pas vraiment d'autre option que d'utiliser Gotoou un Else.

Jon Egerton
la source
2

Salut, je suis également confronté à ce problème et je le résolve en utilisant l'exemple de code ci-dessous

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 
Singaravelan
la source
Je ne sais pas pourquoi cela a été voté à la baisse et la réponse suivante a plus de 100 votes positifs, et ils sont la même réponse!
rryanp
4
Probablement parce que cette réponse a été écrite 5 ans après cette réponse, et c'est exactement le même concept. Pourquoi cela devrait-il recevoir des votes positifs?
Tyler StandishMan
-2

Essayez peut-être de mettre tout cela à la fin si et d'utiliser un autre pour ignorer le code, cela fera en sorte que vous ne puissiez pas utiliser le 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
richo7
la source