- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个带有 24 层嵌套 IF 语句的子程序
l=2
While l <= lmax 'lmax = 15000
If condition1 Then
If condition2a or condition2b Then
...
If condition24 then
ReDim Preserve propositions(UBound(propositions) + 1)
propositions(UBound(propositions)) = l
由于这个子程序被调用了250次,IF语句被调用了250 * 15000次,因此性能是一个大问题。 (宏运行大约需要 23 秒。)
当我编写Ifcondition2a或condition2bThen
时,如果条件2a为真,VBA是否检查条件2b? (即,是否应该对 a 和 b 进行排序,以便 a 的正确率低于 b?)
PS:当然,条件1与2已经订购。
正如 @iDevlop 所说,简短的答案似乎是 VBA 不允许“短路评估”( See this post )
我的问题是 VBA 从工作表读取/访问数据(而不是 VBA 计算 IF 语句。)。
解决方案是在二维数组中加载数据。这个单一的修改使我的 Sub 运行速度快了 10 倍以上(不到 2 秒 vs 23 秒)。
这是我的声明的较短(17 深)版本:
With Sheets("Sheet1")
lmax = .Cells(100000, 1).End(xlUp).Row 'Usually 14000
l = 2
While l <= lmax
If boolean_ignore_param1 Or Left(.Cells(l, 1).Formula, Len(param1)) = param1 Then
If boolean_ignore_param2 Or Left(.Cells(l, 2).Formula, Len(param2)) = param2Then
If (param_boolean_A And .Range("AF" & l).Formula = "Yes") Or (param_boolean_B And .Range("Ag" & l).Formula = "Yes") Then
If (.Cells(l, 6).Formula = "" Or .Cells(l, 6).Value - marge <= param3 Or param3= 0) Then
If (.Cells(l, 7).Formula = "" Or .Cells(l, 7).Value + marge >= param3 Or param3 = 0) Then
If (.Cells(l, 8).Formula = "" Or .Cells(l, 8).Value - marge <= param4 Or param4 = 0) Then
If (.Cells(l, 9).Formula = "" Or .Cells(l, 9).Value + marge >= param4 Or param4 = 0) Then
If (.Cells(l, 10).Formula = "" Or .Cells(l, 10).Value - marge <= param5 Or param5 = 0) Then
If (.Cells(l, 11).Formula = "" Or .Cells(l, 11).Value + marge >= param5 Or param5 = 0) Then
If (.Cells(l, 12).Formula = "" Or .Cells(l, 12).Value <= param6 Or param6 = 0) Then
If (.Cells(l, 13).Formula = "" Or .Cells(l, 13).Value >= param6 Or param6 = 0) Then
If (.Cells(l, 16).Formula = "" Or .Cells(l, 16).Value - marge <= param7 Or param7 = 0) Then
If (.Cells(l, 17).Formula = "" Or .Cells(l, 17).Value + marge >= param7 Or param7 = 0) Then
If (.Cells(l, 18).Formula = "" Or .Cells(l, 18).Value - marge <= param8 Or param8 = 0) Then
If (.Cells(l, 19).Formula = "" Or .Cells(l, 19).Value + marge >= param8 Or param8 = 0) Then
If (.Cells(l, 22).Formula = "" Or .Cells(l, 22).Value - marge <= param9 Or param9 = 0) Then
If (.Cells(l, 23).Formula = "" Or .Cells(l, 23).Value + marge >= param9 Or param9 = 0) Then
ReDim Preserve propositions(UBound(propositions) + 1)
propositions(UBound(propositions)) = l
最佳答案
您可以使用Select Case
代替or用逗号分隔的条件列表如下:
'If condition2a Or condition2b Then
Select Case True
Case condition2a, condition2b 'here comma means lazy 'OR' (like as OrElse in vb.net)
's = s + 10
Case Else
's = s + 20
End Select
此外,如果我们可以看到您的代码,则可能有很多地方可以提高您的宏性能。立即,重新调整数组以向其中添加一项在循环中可能会非常耗时:
ReDim Preserve propositions(UBound(propositions) + 1)
您可以考虑在每次达到其长度时将其 ubound 增加为 10 或 100 个项目(为下一次可能的用途保留一些空间),但将实际的上限索引保留在变量中...
<小时/>更新:
当您添加代码的某些部分时,我可以建议您为每个 if 使用一些辅助函数,如下所示:
替换x<param
if
的:
If (.Cells(l, 6).Formula="" Or .Cells(l, 6).Value-marge<=param3 Or param3=0) Then ...
类似于:
If test(.Cells(l, 6).Value, marge, param3) Then ...
'or without '.Value': If test(.Cells(l, 6), marge, param3) Then ...
我们可以定义这个函数:
Function testLesser(v As Variant, marge As Double, param As Double) As Boolean
'testLesser = (v = "" Or v - marge <= param3 Or param3 = 0)
If v = "" Then
ElseIf v - marge <= param Then
ElseIf param = 0 Then
Else
testLesser = False: Exit Function
End If
testLesser = True
'** Another option (using Select Case):
'Select Case True
'Case v = "", v - marge <= param, param = 0
' testLesser = True
'Case Else
' testLesser = False
'End Select
End Function
对于 if
的其他类型(大于)类似s:
If (.Cells(l, 7).Formula="" Or .Cells(l, 7).Value+marge>=param3 Or param3=0) Then ...
我们有:
Function testGreater(v As Variant, marge As Double, param As Double) As Boolean
'testGreater = (v = "" Or v + marge >= param Or param = 0)
If v = "" Then 'testLesser = True
ElseIf v + marge >= param Then 'testLesser = True
ElseIf param = 0 Then 'testLesser = True
Else
testLesser = False: Exit Function
End If
testLesser = True
'** Another option (using Select Case):
'Select Case True
'Case v = "", v + marge >= param, param = 0
' testLesser = True
'Case Else
' testLesser = False
'End Select
End Function
因此,代码将如下所示:
'If (.Cells(l, 6).Formula = "" Or .Cells(l, 6).Value - marge <= param3 Or param3 = 0) Then
'If (.Cells(l, 7).Formula = "" Or .Cells(l, 7).Value + marge >= param3 Or param3 = 0) Then
'If (.Cells(l, 8).Formula = "" Or .Cells(l, 8).Value - marge <= param4 Or param4 = 0) Then
'If (.Cells(l, 9).Formula = "" Or .Cells(l, 9).Value + marge >= param4 Or param4 = 0) Then
'...
If testLesser(.Cells(l, 6), marge, param3) Then
If testGreater(.Cells(l, 7), marge, param3) Then
If testLesser(.Cells(l, 8), marge, param4) Then
If testGreater(.Cells(l, 9), marge, param4) Then
'...
我的真实测试表明它更快! (显然,它的代码也更具可读性)
注意:
安排 if 条件非常重要,以便尽快获得最终条件!例如,如果单元格值通常为空,则首先将该条件放入我们的测试函数中,但如果 param = 0 通常为 true,则将其作为第一个条件检查...
这是 x OR y
的规则标准。对于“x AND y”条件,则相反!最罕见的情况必须首先快速过滤结果。在您的代码中,我看到您安排了来自 Cells(l, 6)
的嵌套 if至Cells(l, 23)
。我不知道这是否最适合您的情况。这取决于您的数据和通常情况,因此请考虑修改嵌套 if
的顺序如果您知道有些通常是错误的...
另一个提示:
而不是使用 With Sheets("Sheet1")
,将其缓存在变量中,这样可以提高性能!
Dim mySheet As Worksheet
Set mySheet = Sheets("Sheet1")
With mySheet 'Sheets("Sheet1")
我的测试显示这个简单的引用更改速度大约10%。在处理工作表、范围、单元格时,您可能会想到其他类似的更改...
注意:如果我们可以定义marge
作为全局或工作表级别的变量,我们可以将其从函数参数中删除,但似乎它没有明显的效果......
最后更新:
按照 @Ioannis 在评论中的建议 (see also this ref)当处理大量单元格时,最好将值加载到二维数组中并使用它,而不是直接访问单元格:
myArray = Sheets("Sheet1").Range("A1:AG15000").Value
然后使用该数组进行读/写:
myArray(row, col) = myArray(row, col) + 1
'row = 1 to UBound(myArray, 1) 'First array dimension is for rows
'col = 1 to UBound(myArray, 2) 'Second array dimension is for columns
最后,当你完成后,你可以反向更新整个范围:
Sheets("Sheet1").Range("A1:AG15000") = myArray
关于VBA : Performance on 24-deep nested IF statement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42086239/
我有一个 VBA 脚本,可以将数据从一张表复制到另一张表。复制的数据被放入公式中,计算出的数量被复制回原始工作表。我正在尝试获取它,以便 VBA 脚本为每一行执行此操作。我有 1000 行数据。 Su
如何让 excel 在我的“临时”表上列出所有可用的环境变量?下面的代码没有为我返回任何东西...... Sub ListEnvironVariables() Dim strEnviron A
好的,这就是我想要完成的事情:我正在尝试将所有 VBA 代码从“Sheet2”复制到“Sheet 3”代码 Pane 。我不是指将模块从一个模块复制到另一个模块,而是指 Excel 工作表对象代码。
我正在做一个项目来使用 rule-triggered 处理一些传入的 Outlook 邮件。 VBA 代码。 但是,我不想在代码需要更改的任何时候手动更新每个用户收件箱的代码。所以我的想法是把一个文本
我想从另一个代码 VBA 中评论包含 Msg Box 的行。我正在尝试使用 Library VBA EXTENSIBILITY,但我没有找到解决方案。 欢迎任何帮助。 这是我的代码: Sub Comm
我正在尝试编写程序的最后一部分,我需要从 Access 文档中提取数据并将其打印到新的工作簿中。 首先,我将获取产品供应商的名称并创建一个包含每个供应商名称的工作表,然后我想遍历每个工作表并打印每个供
我有一个要求,我试图查找数据中的日期是否大于或等于当前日期,那么它应该显示"is"。 这是我的代码, RDate = Application.WorksheetFunction.if(RSDate>=
我试图想出一个宏来检查单元格中是否存在任何数字值。如果存在数字值,请复制该行的一部分并将其粘贴到同一电子表格内的另一个工作表中。 Sheet1 是包含我所有数据的工作表。我正在尝试查看 R 列中是否有
我有一个具有密码保护(防止未经授权访问宏)的 VBA 宏,它按预期运行。用户单击按钮,宏运行。内容大致如下: Sub sample() ActiveSheet.Unprotect Pass
我想通过VBA删除工作表中包含的VBA代码。目前,我有一个代码可以将工作表复制到新工作簿并从中删除所有图像。但是,这些图像被设置为在代码中的 Worksheet_Activate 上执行操作,每当我轻
我有一个 vba 代码,它指定要查看的特定工作表名称,例如工作表 2, 但是,如果有人忘记将工作表名称更改为sheet2,我可以添加一段动态代码来自动更改调用工作表名称的vba代码吗?例如,从左边算起
VBAExcel 2016 如果执行某些代码后该范围的列数较少,我将尝试动态调整该范围的大小。引用了 MS 文件和各种在线示例,但没有成功。 https://msdn.microsoft.com/en
我在任何地方都找不到这个问题。在 Visual Basic (excel) 中,我可以按 F8 并循环浏览每一行。但是假设我想开始子程序,然后在执行前两行之后,我想跳到第 200 行。到目前为止,我一
这是我昨天的问题的补充,所以我开始一个新问题。基本上,我在 excel 的工作表上得到不同范围的数据,并且数据范围每周都不同,因此最后使用的列和最后使用的行会有所不同。 我想根据名称合并第 3 行和第
我的想法是创建一个函数来传递这样的双数组: Function pass(a() As Double, b() as double) As Boolean Dim i As Integer, j As
我正在使用 vlookup 运行 VBA 代码,但是,它需要几秒钟才能完成,尽管具有行的工作表只有不到 150 行。 滞后主要出现在 col 23 的生成期间。 包含此代码的主工作表有大约 2300
我在 VBA 中有一个小问题,我想将 Range 函数的行和列以 String 格式放置,如下所示: debut = "BH" & LTrim(Str(i)) fin = "DB" &
我正在尝试使用 Visual Basic 编写 Webcrawler。我有一个包含链接的列表,存储在 Excel 中(第 1 列)。然后宏应打开每个链接并将网站中的某些信息添加到 excel 文件中。
我正在尝试自动生成报告(请原谅我缺乏 Excel 经验),但遇到了这个错误。在单元格中显示#NAME。代码应为工作簿另一页上的所有列 E 选择单元格和 COUNTIF <1。这是一个简单的语法错误吗?
我正在使用“Sheet1”上的命令按钮使用 VBA 创建图表,但是该图表正在添加到另一个工作表(“Sheet2”)。 添加图表后,我使用以下代码根据 DataLabel 值对条形图进行着色并更改 Da
我是一名优秀的程序员,十分优秀!