【发布时间】:2020-08-07 04:43:29
【问题描述】:
我有一个包含 55.000 行的数据集,其中包含 35.000 个电子邮件地址,其中 31.000 个是唯一的,因此几个用户占据了多行。我需要找到这些用户的行并将它们添加到类对象中。
将电子邮件列加载到数组中并执行 MATCH/INDEX 查找需要 200 秒。目前可以接受,但对于 200-500K 数据集的预期用途来说,速度肯定不够快。
Dim StartTime As Double
Dim SecondsElapsed As Double
StartTime = Timer
Dim dict As Dictionary
Set dict = CreateObject("scripting.dictionary")
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
Set UserRange = Range(Cells(2, 11), Cells(LastRow, 11))
For Each cell In UserRange
dict(cell.value) = dict(cell.value) + 1
Next
Debug.Print "Number of users: " & dict.Count
UserArray = Range(Cells(2, 11), Cells(LastRow, 11))
UserArray = WorksheetFunction.Transpose(WorksheetFunction.Transpose(WorksheetFunction.Transpose(UserArray)))
For Each User In dict
Dim UserIndex() As Variant
ReDim UserIndex(1 To dict(User))
For i = 1 To dict(User)
Row = WorksheetFunction.Match(User, UserArray, 0)
UserIndex(i) = Row
UserArray(Row) = Empty
Next
For i = LBound(UserIndex) To UBound(UserIndex)
Debug.Print User, UserIndex(i)
Next
Next
SecondsElapsed = Round(Timer - StartTime, 2)
Debug.Print "This code ran successfully in " & SecondsElapsed & " seconds"
我可能会基于源构建一个基于块的索引(每个导入的文件 +-10.000 个条目都有一个 start- 和 endrow),并通过仅查看适当的块来加速它。但也许还有其他方法?
【问题讨论】:
-
您致力于使用 Excel 吗?如果您将数据转储到 Access 中,您可以轻松/快速地运行一些 SQL 来返回重复项。
-
Excel VBA 是我现在所拥有的。这是一段冗长而复杂的代码的最后一步。
-
工作表不是为此而制作的,您需要一个实际的数据库。
Application.Transpose也有局限性:此解决方案无法扩展。您可以做的一件事是在第一个循环中,使用For循环迭代Range(...).Value,而不是使用Range并为源范围中的每个单元格拉动Range.Value两次:您将访问整个源数据的工作表一次,而不是UserRange中的每个单元格一次。请注意,其中有许多隐式 ActiveSheet 引用,可能会在以后引起问题。 -
如果您不使用 debug.print 而是在最后将整个内容写入文本文件或类似的东西,您可以节省一点时间。将 20k+ 转储到即时窗口似乎没有必要。循环内的 redim 可能也无济于事。
-
字典在 0.42 秒内构建,因此访问工作簿不是这里的瓶颈。 Debug.Print 我已经关闭了整个操作(它只在我不循环时才出现)。真正需要时间的是循环和匹配/索引。
标签: excel vba indexing match vlookup