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) < 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>=Schedule(i, 1))
。 (如果测试是 50/50 则无需优化)
可能会有很多嵌套的 if 有点混乱......例如,如果您需要在每次迭代中检查相当多的 Application.Match 结果,以便在使用结果之前找不到匹配项。但就这样吧,生活中还有更糟糕的事情!【参考方案4】:
Continue For
在 VBA 或 VB6 中无效。
从this MSDN page 看来,它似乎已在 VS 2005./Net 2 中引入 VB.Net。
正如其他人所说,除了使用Goto
或Else
,别无选择。
【讨论】:
【参考方案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循环迭代的主要内容,如果未能解决你的问题,请参考以下文章