微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否有比 vba 宏中的 foreach 循环更快的选项?

如何解决是否有比 vba 宏中的 foreach 循环更快的选项?

我正在尝试创建一个宏来格式化我的库存表。我只需要显示最多 8 的值,然后显示超过 9 的任何值。我还需要去掉任何 0 或负数。

我需要在 C、D、E 和 F 列上运行此循环 4 次,并且文件长约 15,000 行。该代码在我调试时有效,但如果它只是运行,它会使应用程序崩溃。我知道我不能循环那么多,但还有其他方法可以做到吗?

Call SetStockLevels(range("C3:C" & lastRow))

Private Sub SetStockLevels(range As range)

    For Each c In range
        If c.Value < 1 Then
            c.ClearContents
        ElseIf c.Value > 8 Then
            c.Value = "9+"
        End If
    Next

End Sub

我已经分别在宏的开头和结尾调用了这些函数

Public Sub speedup()

    Application.ScreenUpdating = False
    Application.displayStatusBar = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False

End Sub

Public Sub normal()

    Application.ScreenUpdating = True
    Application.displayStatusBar = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True

End Sub

解决方法

此方法将范围值存储在数组中并从中进行处理,这应该比逐个单元格循环要快得多。

如果 C-F 列中的起始行和结束行相同,则可以传递整个范围并一起处理。

Option Explicit

Private Sub Test()
    Dim lastRow As Long
    lastRow = Sheet1.Range("C" & Sheet1.Rows.Count).End(xlUp).Row
    
    SetStockLevels Sheet1.Range("C3:F" & lastRow)
End Sub

Private Sub SetStockLevels(setRng As Range)

    Dim tempArr As Variant
    
    tempArr = setRng.Value
    
    Dim i As Long
    Dim j As Long
    For j = LBound(tempArr,2) To UBound(tempArr,2)
        For i = LBound(tempArr,1) To UBound(tempArr,1)
            Select Case tempArr(i,j)
                Case Is < 1: tempArr(i,j) = ""
                Case Is > 8: tempArr(i,j) = "9+"
            End Select
        Next i
    Next j
    
    setRng.Value = tempArr
End Sub
,

使用正则表达式

进行实验

我认为正则表达式替换会更快,但它需要几乎相似的时间......

Sub SetStockLevels()
Dim StartTime As Double
Dim SecondsElapsed As Double
'Remember time when macro starts
  StartTime = Timer
'________________Timer Start_______________
Dim myrng As Range,mystr As String,arr,col As Range
Dim lastRow As Long,i As Long

Dim regex As Object,mc As Object
Set regex = CreateObject("VBScript.regexp")
regex.ignorecase = False
regex.Global = True

lastRow = Sheet1.Range("C" & Sheet1.Rows.Count).End(xlUp).Row
Set myrng = Sheet1.Range("C3:F" & lastRow)

For Each col In myrng.Columns
    mystr = "," & Join(Application.Transpose( _
        Application.Index(col.Value,1)),",") & ","
    
    regex.Pattern = "-\d*(\.?\d*)" 'for negative numbers including decimal
    mystr = regex.Replace(mystr,"")
    regex.Pattern = "," 'for zeros
    mystr = regex.Replace(mystr,")
'__________________________________________________________________
    'for numbers with decimals skip below two regex replacements _
    'and use the loop below. Not sure how to get regex match for decimals > 8
    regex.Pattern = "[0-9]{2,}" 'for numbers greater than 9
    mystr = regex.Replace(mystr,"9+")
    regex.Pattern = ",9," 'for Nine (Single digit)
    mystr = regex.Replace(mystr,9+,")
'__________________________________________________________________

    arr = Split(Mid(mystr,2,Len(mystr) - 2),")
    
'    For i = 0 To UBound(arr)
'        If arr(i) <> "" And arr(i) > 8 Then arr(i) = "9+"
'    Next i
    
    col.Value = Application.Transpose(arr)
Next col

'________________Timer End_______________
'Determine how many seconds code took to run
  SecondsElapsed = Round(Timer - StartTime,2)
'Notify user in seconds
  Debug.Print "This code ran successfully in " & SecondsElapsed & " seconds",vbInformation

End Sub

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。