VBA - jak warunkowo pominąć iterację pętli for


101

Mam pętlę for na tablicy. To, co chcę zrobić, to przetestować określony warunek w pętli i przejść do następnej iteracji, jeśli to prawda:

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

Wiem, że potrafię:

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

ale chcę mieć możliwość zapisania ostatniej wartości i w zmiennej PrevCouponIndex.

Jakieś pomysły?

Dzięki


3
Powiedziałeś: „Wiem, że potrafię: If (Schedule(i, 1) < ReferenceDate) Then Continue For” Jesteś tego pewien? Continuenie jest słowem kluczowym VBA.
mwolfe02

@ mwolfe02 - nie, nie jestem pewien, ale widziałem gdzieś w przykładach (cpearson?)
Richard H,

mógł być przykładem VB.NET
typ anonimowy

Odpowiedzi:


31

Nie mógłbyś po prostu zrobić czegoś takiego?

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
Rzeczywiście, to jest dokładnie to, co zrobiłem :) Ale wciąż mnie to denerwuje, że muszę zawijać rzeczy w inny kawałek. Dzięki
Richard H,

4
+1 @RichardH cóż, musisz użyć IFdo testu, więc nie jest to aż tak drogie. Powinieneś jednak upewnić się, że najczęstszym wynikiem jest to, że Schedule(i, 1)jest mniej niż ReferenceDateunikanie wykonywania Elseczęściej niż to konieczne. W przeciwnym razie użyj (ReferenceDate>=Schedule(i, 1)). (jeśli test jest 50/50, to nie ma potrzeby optymalizacji)
brettdj

Po prostu może być trochę bałagan z wieloma zagnieżdżonymi ifs ... jeśli na przykład musisz sprawdzić sporo wyników Application.Match w każdej iteracji, aby nie znaleźć dopasowania przed użyciem wyników. Ale niech tak będzie, w życiu są gorsze rzeczy!
JeopardyTempest

183

VBA nie ma Continueani żadnego innego równoważnego słowa kluczowego, aby natychmiast przejść do następnej iteracji pętli. Sugerowałbym rozsądne użycie Gotojako obejścia, zwłaszcza jeśli jest to tylko wymyślony przykład, a twój prawdziwy kod jest bardziej skomplikowany:

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

Jeśli to naprawdę cały twój kod, @Brian jest absolutnie poprawny. Po prostu umieść Elseklauzulę w swoim Ifoświadczeniu i skończ z tym.


18
Dzięki, to dobra wskazówka, jeśli chodzi o GoTo (VBA - przenosi cię z powrotem do 1964 r.)
Richard H,

3
@George: GoTo może być nadużywane (dlatego zakwalifikowałem moje oświadczenie; patrz rozsądne ), ale nie jest ono z natury złe. Poważnie, nie można napisać solidnego języka VBA bez instrukcji Goto tylko dlatego, że jest on potrzebny do obsługi błędów (tj On Error Goto.).
mwolfe02

3
@George: To, co tu zalecam, to obejście innego ograniczenia języka (brak Continueinstrukcji). Można argumentować, że Continuenależy unikać używania haseł w innych językach, a zatem również tutaj. W pewnym sensie link, który opublikowałeś, daje mi do zrozumienia. Link prowadzi do GoToinstrukcji w VB.Net. VB.Net ma zarówno strukturalną obsługę błędów, jak i Continue For/ Continue Doinstrukcje. Naprawdę nie ma takiej potrzeby GoTow VB.Net; Podejrzewam, że pozostawiono go w dużej mierze w celu ułatwienia konwersji istniejącego kodu VBA / VB6.
mwolfe02

4
@George GoToma tę zaletę, że ogranicza zagnieżdżanie. Pomijanie iteracji pętli bez dodawania poziomu wcięć jest, IMO, jednym z niewielu legalnych zastosowań GoTow VBA / VB6. Zwłaszcza jeśli wyodrębnisz ciało pętli do własnej procedury .
Mathieu Guindon

4
@George Widziałem zagnieżdżanie, które nie łamie kodu , ale niszczy mózg ;)
Mathieu Guindon

35

Możesz użyć pewnego rodzaju continue, używając zagnieżdżonego 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
ciekawe .. lepsze niż użycie goto!
ozmike

To jest niesamowite
Kubie

1
To powinna być odpowiedź
Stian Ulriksen

Bardzo eleganckie i ładne
Alexis Sánchez Tello

5
Sprytny! Jednak nie chciałbym być facetem, który spotyka to bez komentarzy. lol
Caltor

14

Continue For nie działa w VBA lub VB6.

Na tej stronie MSDN wygląda na to, że została wprowadzona do VB.Net w VS 2005./Net 2.

Jak powiedzieli inni, tak naprawdę nie ma innej opcji niż użycie Goto lub Else.


2

Cześć, mam również ten problem i rozwiązuję go za pomocą poniższego przykładowego kodu

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 

Nie jestem pewien, dlaczego głosowano w dół, a następna odpowiedź ma ponad 100 głosów pozytywnych i to ta sama odpowiedź!
rryanp

4
Prawdopodobnie dlatego, że ta odpowiedź została napisana 5 lat po tej odpowiedzi i jest to dokładnie ta sama koncepcja. Dlaczego powinno to otrzymać głosy za?
Tyler StandishMan

-2

Może spróbuj umieścić to wszystko na końcu, jeśli i użyj else, aby pominąć kod, co spowoduje, że nie będziesz mógł używać 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.