VBA - 如何有条件地跳过for循环迭代

Posted

技术标签:

【中文标题】VBA - 如何有条件地跳过for循环迭代【英文标题】:VBA - how to conditionally skip a for loop iteration 【发布时间】:2012-01-30 15:01:12 【问题描述】:

我在一个数组上有一个 for 循环。我想要做的是测试循环中的某个条件,如果为真则跳到下一次迭代:

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

我知道我能做到:

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

但我希望能够在 PrevCouponIndex 变量中记录 i 的最后一个值。

有什么想法吗?

谢谢

【问题讨论】:

你说:“我知道我能做到:If (Schedule(i, 1) &lt; ReferenceDate) Then Continue For”你确定吗? Continue 不是 VBA 关键字。 @mwolfe02 - 不确定,但在某处的示例中看到(cpearson?) 可能是 VB.NET 示例 Continue 是一个 VB 关键字(在 VS2017 中),但不幸的是,这不是。可能在 C#(或 C++ 或 C)中看到了一个示例。 【参考方案1】:

VBA 没有Continue 或任何其他等效关键字来立即跳转到下一个循环迭代。我建议明智地使用Goto 作为解决方法,特别是如果这只是一个人为的示例并且您的实际代码更复杂:

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

如果这真的是你所有的代码,那么@Brian 是绝对正确的。只需在 If 语句中添加 Else 子句即可。

【讨论】:

谢谢,这是关于 GoTo 的一个很好的提示(VBA - 让您回到 1964 年) @George:GoTo 可以被滥用(这就是我限定我的声明的原因;参见judicious),但它本质上并不是邪恶的。不过说真的,不可能在没有 Goto 语句的情况下编写健壮的 VBA,仅仅因为您需要它来处理错误(例如,On Error Goto)。 @George:我在这里推荐的是另一种语言限制的解决方法(没有Continue 声明)。有人可能会争辩说,应该避免在其他语言中使用Continue,因此这里也应该避免。在某些方面,您发布的链接说明了我的观点。该链接指向 VB.Net 中的 GoTo 语句。 VB.Net 有结构化错误处理和Continue For/Continue Do 语句。 VB.Net 中确实不需要GoTo;我怀疑它主要是为了支持更轻松地转换现有 VBA/VB6 代码。 @George GoTo 有减少嵌套的好处。在不添加缩进级别的情况下跳过循环迭代是,IMO,GoTo 在 VBA/VB6 中为数不多的合法用途之一。特别是如果你extract the loop's body into its own procedure. @George 我见过嵌套不会破坏代码,但会破坏一个人的大脑 ;)【参考方案2】:

您可以通过使用嵌套的Do ... Loop While False 来使用一种continue

'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

【讨论】:

有趣..比使用 goto 更好! 这太棒了 这应该是答案 聪明!不过,我不想成为那个没有 cmets 的人。大声笑 我同意这个解决方案有一定的聪明之处,但不同意它的优雅。它实际上掩盖了正在完成的事情,使编码变得不那么不言自明,需要评论来解释它(正如 Caltor 所指出的)。【参考方案3】:

你就不能做一些像这样简单的事情吗?

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

【讨论】:

确实,这正是我所做的 :) 但它仍然困扰着我,我必须将东西包装在 Else 中。谢谢 +1 @RichardH 好吧,您必须使用 IF 进行测试,所以这在代码方面并不是那么昂贵。您应该确保最常见的结果是Schedule(i, 1) 小于ReferenceDate,以避免不必要地执行Else。否则使用(ReferenceDate&gt;=Schedule(i, 1))。 (如果测试是 50/50 则无需优化) 可能会有很多嵌套的 if 有点混乱......例如,如果您需要在每次迭代中检查相当多的 Application.Match 结果,以便在使用结果之前找不到匹配项。但就这样吧,生活中还有更糟糕的事情!【参考方案4】:

Continue For 在 VBA 或 VB6 中无效。

从this MSDN page 看来,它似乎已在 VS 2005./Net 2 中引入 VB.Net。

正如其他人所说,除了使用GotoElse,别无选择。

【讨论】:

【参考方案5】:

您好,我也遇到了这个问题,我使用下面的示例代码解决了这个问题

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 

【讨论】:

不知道为什么这被否决了,下一个答案有超过 100 票赞成,他们是相同的答案! 可能是因为这个答案是在那个答案 5 年后写的,并且是完全相同的概念。为什么这会得到支持?【参考方案6】:

也许尝试把它全部放在最后 if 并使用 else 来跳过代码,这样你就不能使用 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

【讨论】:

以上是关于VBA - 如何有条件地跳过for循环迭代的主要内容,如果未能解决你的问题,请参考以下文章

字符串长度的for循环奇怪地跳过了一些字符

Python:如果条件为真,则跳过 For 循环中的迭代

vba for循环

如何跳过for-in循环的迭代(Swift 3)

如何在 PHP 的 for 循环中跳过迭代?

我需要一种类似于for循环重新评估测试条件的行为的算法