VBA - como pular condicionalmente uma iteração for loop

101

Eu tenho um loop for sobre uma matriz. O que eu quero fazer é testar uma determinada condição no loop e pular para a próxima iteração se for verdadeira:

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

Eu sei que posso fazer:

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

mas quero ser capaz de registrar o último valor de i na variável PrevCouponIndex.

Alguma ideia?

obrigado

Richard H
fonte
3
Você disse: "Sei que posso fazer: If (Schedule(i, 1) < ReferenceDate) Then Continue For" Tem certeza disso? Continuenão é uma palavra-chave do VBA.
mwolfe02
@ mwolfe02 - não, não tenho certeza, mas vi em exemplos em algum lugar (cpearson?)
Richard H
pode ter sido um exemplo de VB.NET
Tipo anônimo

Respostas:

31

Você não poderia simplesmente fazer algo simples assim?

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
fonte
4
Na verdade, é exatamente o que eu fiz :) Mas ainda me incomoda ter que embrulhar as coisas na peça Else. Obrigado
Richard H
4
+1 @RichardH bem, você tem que usar um IFpara o teste, então não é tão caro assim. Você deve, entretanto, garantir que o resultado mais comum Schedule(i, 1)seja menor do ReferenceDateque evitar a execução com Elsemais freqüência do que o necessário. Caso contrário, use (ReferenceDate>=Schedule(i, 1)). (se o teste for 50/50, não há necessidade de otimização)
brettdj
Pode ficar um pouco confuso com vários ifs aninhados ... se, por exemplo, você precisar verificar alguns resultados Application.Match em cada iteração para não encontrar uma correspondência antes de usar os resultados. Mas que seja, há coisas piores na vida!
JeopardyTempest
183

O VBA não tem uma Continueou qualquer outra palavra-chave equivalente para pular imediatamente para a próxima iteração do loop. Eu sugeriria um uso criterioso de Gotocomo uma solução alternativa, especialmente se este for apenas um exemplo inventado e seu código real for mais complicado:

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 esse for realmente todo o seu código, @Brian está absolutamente correto. Basta colocar uma Elsecláusula em sua Ifdeclaração e pronto.

mwolfe02
fonte
18
Obrigado, essa é uma boa dica sobre o GoTo (VBA - transmitindo você de volta a 1964)
Richard H
3
@George: GoTo pode ser abusado (que é por isso que eu qualificado minha declaração, ver criterioso ), mas não é inerentemente mau. Sério, é impossível escrever um VBA robusto sem a instrução Goto simplesmente porque você precisa dela para tratamento de erros (isto é, On Error Goto).
mwolfe02
3
@ George: O que estou recomendando aqui é uma solução alternativa para outra limitação da linguagem (sem Continuedeclaração). Pode-se argumentar que o uso de Continueem outras línguas deve ser evitado e, portanto, também deve ser evitado aqui. De certa forma, o link que você postou mostra meu ponto. O link é para a GoTodeclaração em VB.Net. O VB.Net tem tratamento de erros estruturado e instruções Continue For/ Continue Do. Realmente não há necessidade de GoToem VB.Net; Suspeito que ele foi deixado no local em grande parte para oferecer suporte à conversão mais fácil do código VBA / VB6 existente.
mwolfe02
4
@George GoTotem a vantagem de reduzir o aninhamento. Ignorar uma iteração de loop sem adicionar um nível de indentação é, IMO, um dos poucos usos legítimos do GoToem VBA / VB6. Especialmente se você extrair o corpo do loop em seu próprio procedimento .
Mathieu Guindon,
4
@George Eu vi aninhamento que não quebra o código , mas destrói o cérebro ;)
Mathieu Guindon
35

Você pode usar um tipo de continueusando um aninhado 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
Exceção não tratada
fonte
1
interessante ..melhor do que usar goto!
ozmike de
Isso é incrível
Kubie
1
Esta deve ser a resposta
Stian Ulriksen
Muito elegante e agradável
Alexis Sánchez Tello
5
Inteligente! Eu odiaria ser o cara que iria encontrar isso sem comentários, no entanto. lol
Caltor
14

Continue For não é válido em VBA ou VB6.

A partir desta página do MSDN , parece ter sido introduzido no VB.Net no VS 2005./Net 2.

Como os outros disseram, não há realmente uma opção diferente de usar Gotoou um Else.

Jon Egerton
fonte
2

Olá, também estou enfrentando esse problema e resolvo isso usando o código de exemplo abaixo

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
fonte
Não tenho certeza por que isso foi votado contra e a próxima resposta tem mais de 100 votos a favor, e eles são a mesma resposta!
rryanp
4
Provavelmente porque essa resposta foi escrita 5 anos depois dessa resposta e é exatamente o mesmo conceito. Por que isso deve receber votos positivos?
Tyler StandishMan
-2

Talvez tente colocar tudo no final se e usar um outro para pular o código, isso fará com que você não consiga usar o 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
fonte