我在Excel VBA代码中过滤和向集合添加数据时遇到问题。
我有两本书:SourceWB和SourceTR。我从两者收集数据,并将它们列在SourceTR中。目标是比较两个数据集并找到不匹配。代码在SourceTR处于活动状态时运行。
我省略了代码的其余部分,这里只是有问题的部分:
Debug.Print "3 -- " & Now
For Each i In Workbooks("SourceTR").Worksheets("Source1").Range("A4:A10000")
If i.Value <> "" Then
If month(i.Value) = selected_month Then
item_1 = Worksheets("Source1").Range("E" & i.row).Value
item_2 = Worksheets("Source1").Range("F" & i.row).Value
item_3 = Worksheets("Source1").Range("K" & i.row).Value
entry = item_1 & "_" & item_2 & "_" & item_3
If IsInCollection(init_tr_entries, entry) = False Then
init_tr_entries.Add (entry)
End If
End If
End If
Next i
Debug.Print "4 -- " & Now
Dim coll_item
For Each coll_item In init_tr_entries
Workbooks("SourceTR").Worksheets("target").Range("A" & starting_row_1).Value = Split(coll_item, "_")(0)
Workbooks("SourceTR").Worksheets("target").Range("B" & starting_row_1).Value = Split(coll_item, "_")(1)
Workbooks("SourceTR").Worksheets("target").Range("C" & starting_row_1).Value = Split(coll_item, "_")(2)
starting_row_1 = starting_row_1 + 1
Next coll_item
Debug.Print "5 -- " & Now
Dim a As Range
Dim user As String
user = Worksheets("vir").Range("G2").Value
Dim init_as_entries As New Collection
For Each a In Workbooks("SourceWB"))).Worksheets("Source2")).Range("BU4:BU10000")
If a.Value <> "" Then
If a.Value = "" & selected_month & "" Then
If Workbooks("SourceWB"))).Worksheets("Source2")).Range("F" & a.row).Value = user Then
item_1 = Workbooks("SourceWB"))).Worksheets("Source2")).Range("A" & a.row).Value
item_2 = Workbooks("SourceWB"))).Worksheets("Source2")).Range("B" & a.row).Value
item_3 = Workbooks("SourceWB"))).Worksheets("Source2")).Range("E" & a.row).Value
entry = item_1 & "_" & item_2 & "_" & item_3
init_as_entries.Add (entry)
End If
End If
End If
Next a
For Each coll_item In init_as_entries
Workbooks("SourceTR").Worksheets("target").Range("F" & starting_row_2).Value = Split(coll_item, "_")(0)
Workbooks("SourceTR").Worksheets("target").Range("G" & starting_row_2).Value = Split(coll_item, "_")(1)
Workbooks("SourceTR").Worksheets("target").Range("H" & starting_row_2).Value = Split(coll_item, "_")(2)
starting_row_2 = starting_row_2 + 1
Next coll_item
Debug.Print "6 -- " & Now
点3和点5之间的代码大约需要1秒,点5和点6之间的代码大约需要10秒。然而,除了一些过滤,我在代码中看不到任何区别。
数据集很小,SourceWB中有2500个非空白行,SourceTR中只有60个。
我做错了什么?
---编辑--我做了一些额外的测量,这部分:
For Each a In Workbooks("SourceWB"))).Worksheets("Source2")).Range("BU4:BU10000")
If a.Value <> "" Then
If a.Value = "" & selected_month & "" Then
If Workbooks("SourceWB"))).Worksheets("Source2")).Range("F" & a.row).Value = user Then
item_1 = Workbooks("SourceWB"))).Worksheets("Source2")).Range("A" & a.row).Value
item_2 = Workbooks("SourceWB"))).Worksheets("Source2")).Range("B" & a.row).Value
item_3 = Workbooks("SourceWB"))).Worksheets("Source2")).Range("E" & a.row).Value
entry = item_1 & "_" & item_2 & "_" & item_3
init_as_entries.Add (entry)
End If
End If
End If
Next a
使用此速度增强只需7秒:
Application.ScreenUpdating = False
Application.Calculation = xlManual
Application.EnableEvents = False
Application.DisplayStatusBar = False
ActiveSheet.DisplayPageBreaks = False
3条答案
按热度按时间lymnna711#
要清理代码(这基本上不是速度问题),请使用Workbook和Worksheet变量:
并且对于目标工作簿/工作表也类似。
现在是加速:VBA正在减慢的是Excel和VBA之间的接口。因此,你能做的最好的事情就是将 * 所有 * 相关的数据读入一个数组,然后循环遍历。此外,您应该检查最后一行数据是什么。阅读Find last used cell in Excel VBA以获得详细讨论,我将使用最常见的方法作为示例,检查是否适合您。下面的代码模拟了步骤3的逻辑:
现在,您有了一个二维数组,其中包含第一个源工作表的数据副本。即使这是一个相当大的数组,阅读也不会比只读取单个数据单元慢多少。
您可以循环访问内存中的数据(这是即时发生的,您将无法测量执行时间)
写入数据也是如此:用要写入的数据准备一个数组
现在您有了一个可以一次性写入的二维数据数组。我使用了一个中间范围变量,但这只是为了更好的可读性:
ubof19bj2#
我终于找到了根本原因。我是通过使用如上所述的新工作簿到达那里的。但是,它不是格式和公式,而是工作簿名称。我在代码中通过工作簿的名称引用了它,而以前我使用查找函数来获取源工作簿的名称。
我试图解决的excel解决方案是一个更大的工作簿,模块和函数集的一部分,它们有几种语言(宏和工作簿)。因此,工作簿名称会更改。因此,我调用
Workbooks(replaceYearInStr(getTranslation("some_wb_codename")))
以得到Workbooks("SourceWB")
。根据后端语言集的不同,可能会得到斯洛文尼亚语的Workbooks("IzvorWB")
。getTranslation
函数使用lookup从语言工作表中获取名称,所以看起来这个函数会减慢它的速度。我仍然不想硬编码的名字,但至少我知道问题是什么。jchrr9hc3#
你试过使用脚本吗?字典对象而不是集合?我有传闻证据表明,它们明显(也许不是数量级,但明显)比VBA中的集合快。使用CreateObject(“Scripting.Dictionary”)创建对象,而不必设置对Microsoft脚本运行时的引用,并将其分配给通用对象。