大循环在 VBA 中崩溃
Big loop crashes in VBA
截图
我正在用另一个列表 (1) 的频率排名更新单词列表 (2)。该代码旨在为列表 1 中的每个条目遍历列表 2,并将频率排名添加到其中的每个相同条目。如果我将列表限制为每个列表中的几个条目,它会完全按预期工作,但列表非常大。列表 1 包含 55.000 个单词,列表 2 包含 18.000 个单词。有没有办法防止代码崩溃,或者以更有效的方式重写代码?我确信它远非最佳,因为我是 VBA 的完全新手。我将粘贴下面的代码。
非常感谢
Option Explicit
Sub CorrectFrequencyData()
Dim Frequency As Double
Dim CurrentLocation As Range
Application.ScreenUpdating = False
Set CurrentLocation = Range("i5")
Do Until CurrentLocation.Value = ""
Frequency = CurrentLocation.Offset(0, -6).Value
Range("n4").Activate
Do Until ActiveCell.Value = ""
If ActiveCell.Value = CurrentLocation.Value Then ActiveCell.Offset(0, 1).Value = ActiveCell.Offset(0, 1).Value + Frequency
ActiveCell.Offset(1, 0).Activate
Loop
Set CurrentLocation = CurrentLocation.Offset(1, 0)
Loop
Application.ScreenUpdating = True
End Sub
看起来可能有几种方法可以加速您的代码。首先,您可以使用 SUMIF
,正如 GavinP 在您的第二个频率列中所建议的那样 =SUMIF(I:I, N4, C:C)
如果您将其向下流动到您的第二个频率列,这就是说检查第 I 列中 N + 行中的值以及在从 C 列到总计的频率处找到该值的所有地方。
现在可以选择加速您的代码:
Option Explicit
Sub CorrectFrequencyData()
Application.ScreenUpdating = False
我不确定您的代码中是否有公式,但您可以将它们设置为手动,而不是每次更改 sheet 上的值时都重新计算它们。
Application.Calculation = -4135 'xlCalculationManual
您可以将范围分配给一个数组,然后循环遍历速度更快的数组,而不是循环遍历您的 sheet。我们还可以消除为第一个列表中的每个条目遍历第二个列表的需要。我们将通过将第一个单词列表及其频率存储在字典中来做到这一点
Dim ArrWords() as variant
Dim LastRow as long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 9).End(-4162).Row 'Version non-specific Endrow, xlUP
ArrWords = Range("C4:I" & LastRow)
Dim dicWordFrequency as Object
Set dicWordFrequency = CreateObject("Dictionary.Scripting")
Dim tempWord as String
Dim i as Long
For i = 1 to Ubound(ArrWords)
tempWord = arrWords(i,7)
If not dicWordFrequency.Exists(tempWord) then
DicWordFrequency.Add tempWord, arrWords(i,1)
Else
DicWordFrequency.Item(tempWord)= dicWordFrequency.Item(tempWord) + arrWords(i,1)
End If
Next
现在我们可以遍历您的作品sheet并更新第二个列表中单词的频率。
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 14).End(-4162).Row 'Version non-specific Endrow, xlUP
ArrWords = Range("N4:O" & LastRow)
For i = 1 to Ubound(arrWords)
tempWord = arrwords(i,1)
If dicWordFrequency.Exists(tempWord) then
arrWords(i,2) = dicWordFrequency.Item(tempWord)
End If
Next
'Dump your new array with the totals to a range
Dim result as Range
Set Result = Range("N4")
Result.ReSize(UBound(arrWords,1), Ubound(ArrWords,2)).value = arrWords
Application.ScreenUpdating = True
Application.Calculation = -4105 'xlCalculationAutomatic
End Sub
截图
我正在用另一个列表 (1) 的频率排名更新单词列表 (2)。该代码旨在为列表 1 中的每个条目遍历列表 2,并将频率排名添加到其中的每个相同条目。如果我将列表限制为每个列表中的几个条目,它会完全按预期工作,但列表非常大。列表 1 包含 55.000 个单词,列表 2 包含 18.000 个单词。有没有办法防止代码崩溃,或者以更有效的方式重写代码?我确信它远非最佳,因为我是 VBA 的完全新手。我将粘贴下面的代码。
非常感谢
Option Explicit
Sub CorrectFrequencyData()
Dim Frequency As Double
Dim CurrentLocation As Range
Application.ScreenUpdating = False
Set CurrentLocation = Range("i5")
Do Until CurrentLocation.Value = ""
Frequency = CurrentLocation.Offset(0, -6).Value
Range("n4").Activate
Do Until ActiveCell.Value = ""
If ActiveCell.Value = CurrentLocation.Value Then ActiveCell.Offset(0, 1).Value = ActiveCell.Offset(0, 1).Value + Frequency
ActiveCell.Offset(1, 0).Activate
Loop
Set CurrentLocation = CurrentLocation.Offset(1, 0)
Loop
Application.ScreenUpdating = True
End Sub
看起来可能有几种方法可以加速您的代码。首先,您可以使用 SUMIF
,正如 GavinP 在您的第二个频率列中所建议的那样 =SUMIF(I:I, N4, C:C)
如果您将其向下流动到您的第二个频率列,这就是说检查第 I 列中 N + 行中的值以及在从 C 列到总计的频率处找到该值的所有地方。
现在可以选择加速您的代码:
Option Explicit
Sub CorrectFrequencyData()
Application.ScreenUpdating = False
我不确定您的代码中是否有公式,但您可以将它们设置为手动,而不是每次更改 sheet 上的值时都重新计算它们。
Application.Calculation = -4135 'xlCalculationManual
您可以将范围分配给一个数组,然后循环遍历速度更快的数组,而不是循环遍历您的 sheet。我们还可以消除为第一个列表中的每个条目遍历第二个列表的需要。我们将通过将第一个单词列表及其频率存储在字典中来做到这一点
Dim ArrWords() as variant
Dim LastRow as long
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 9).End(-4162).Row 'Version non-specific Endrow, xlUP
ArrWords = Range("C4:I" & LastRow)
Dim dicWordFrequency as Object
Set dicWordFrequency = CreateObject("Dictionary.Scripting")
Dim tempWord as String
Dim i as Long
For i = 1 to Ubound(ArrWords)
tempWord = arrWords(i,7)
If not dicWordFrequency.Exists(tempWord) then
DicWordFrequency.Add tempWord, arrWords(i,1)
Else
DicWordFrequency.Item(tempWord)= dicWordFrequency.Item(tempWord) + arrWords(i,1)
End If
Next
现在我们可以遍历您的作品sheet并更新第二个列表中单词的频率。
LastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 14).End(-4162).Row 'Version non-specific Endrow, xlUP
ArrWords = Range("N4:O" & LastRow)
For i = 1 to Ubound(arrWords)
tempWord = arrwords(i,1)
If dicWordFrequency.Exists(tempWord) then
arrWords(i,2) = dicWordFrequency.Item(tempWord)
End If
Next
'Dump your new array with the totals to a range
Dim result as Range
Set Result = Range("N4")
Result.ReSize(UBound(arrWords,1), Ubound(ArrWords,2)).value = arrWords
Application.ScreenUpdating = True
Application.Calculation = -4105 'xlCalculationAutomatic
End Sub