开发者

Optimizing loop for vba macro excel 2007

I have this code that works. it goes down a range and deletes the empty rows, seperates the first character into a different column if its not a number or negative sign.

This code WORKS. but it is too SLOW for the amount of data i need it to deal with. Thank you anyone for your suggestion on how to optimize this code and make it faster.

I have already turned off automatic calculations. screen updating. and visibility of application.

Dim rng As Range
Dim i As Long
Dim Tracking As Long

Dim textval As String
Dim limitz As String
Dim remaining As String

Range("B1").End(xlDown).Offset(0, 5).Select

Set rng = Range("G2", ActiveCell).Select

i = 1
Range("G2").Select

For Tracking = 1 To rng.Rows.Count

    textval = rng.Cells(i).Value
    limitz = Left(textval, 1)

    If limitz = "" Then
      rng.Cells(i).EntireRow.Delete
     ElseIf limitz <> "0" And limitz <> "1" And limitz <> "2" And limitz <> "3" And limitz <> "4" And limitz <> "5" And limitz <> "6" And limitz <> "7" And limitz <>开发者_开发百科 "8" And limitz <> "9" And limitz <> "-" Then
      remaining = Right(textval, Len(textval) - 1)
      rng.Cells(i) = remaining
      rng.Cells(i).Offset(0, 1).Value = limitz
      i = i + 1
     Else
      i = i + 1
    End If

Next


There is not so much code that seems to be obviously inefficient.

Here is some tips about what I can tell:

  • Don't select cells unless you are really forced too (as it is not within your loop, that is not the worst thing)
  • Try to parse range instead of using a Long
  • Change your test with a vba statement like IsNumeric
  • Use With to avoid calling an object multiple times

Here is a try (i may have changed some behavior because i couldn't understand if you wanted to parse cells or rows):

Sub test()
  Dim rng As Range, row As Range
  Dim i As Long

  Dim textval As String
  Dim limitz As String
  Dim remaining As String

  Set rng = Range("G2", Range("B1").End(xlDown).Offset(0, 5))
  i = 1

  For Each row In rng.Rows
      With row
        textval = .Cells(i).Value
        limitz = Left(textval, 1)

        If limitz = "" Then
            .Cells(i).EntireRow.Delete
        ElseIf limitz <> "-" And Not IsNumeric(limitz) Then
          remaining = Right(textval, Len(textval) - 1)
          With .Cells(i)
            .Value = remaining
            .Offset(0, 1).Value = limitz
          End With
          i = i + 1
         Else
          i = i + 1
        End If
      End With
  Next
End Sub


You should process your rows from the bottom to the top: should be faster beacause each delete causes fewer rows to move up.

Untested:

Sub test()

    Dim rng As Range, c As Range
    Dim numRows As Long
    Dim Tracking As Long

    Dim textval As String
    Dim limitz As String

    Set rng = Range("G2", Range("B1").End(xlDown).Offset(0, 5))
    numRows = rng.Rows.Count

    For Tracking = numRows To 1 Step -1

        Set c = rng.Cells(Tracking)
        textval = c.Value
        limitz = Left(textval, 1)

        If limitz = "" Then
          c.EntireRow.Delete
        ElseIf Not limitz Like "[0-9-]" Then
          c.Value = Right(textval, Len(textval) - 1)
          c.Offset(0, 1).Value = limitz
        End If

    Next

End Sub


This should be pretty speedy. Hope I didn't alter your code too much to change something I shouldn't have.

Grabbing all the data in a variant makes it much faster since the VBA doesn't have to interact with Excel too much. Using special cells also does this. Using "like" cleans the code up, don't know if the performance is any better for that.

Dim rng As Range
Dim vData As Variant
Dim i As Long
Dim limitz As String

Set rng = Range("G2", Range("B1").End(xlDown).Offset(0, 5).Address)

'Delete empty cells
On Error Resume Next
rng.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
On Error GoTo 0

'Get all data in range
vData = rng.Resize(, 2)

For i = 1 To UBound(vData)

    limitz = Left$(CStr(vData(i, 1)), 1)

    If limitz Like "[!0-9,!-]" Then
      vData(i, 1) = Right$(CStr(vData(i, 1)), Len(vData(i, 1)) - 1)
      vData(i, 2) = limitz
    End If
Next

rng.Resize(, 2) = vData

The following code is untested but should work and go pretty fast. It should be noted that deleted entire rows is fairly costly (time wise) to do, although you can minimize the time using the method below, it will still take a while and there's not much you can do about it:

dim bUnion as boolean
Dim rng As Range, rUnion as range
Dim vData As Variant
Dim i As Long
Dim limitz As String

Set rng = Range("G2", Range("B1").End(xlDown).Offset(0, 5).Address)

'Get all data in range
vData = rng.Resize(, 2)

bunion=false
For i = 1 To UBound(vData)

    if len(vdata(i,1))>0 THEN
      limitz = Left$(CStr(vData(i, 1)), 1)

      If limitz Like "[!0-9,!-]" Then
        vData(i, 1) = Right$(CStr(vData(i, 1)), Len(vData(i, 1)) - 1)
        vData(i, 2) = limitz
      End If
    else
      if bunion then 
          set runion=union(runion,range("A" & i+1))
      else
          set runion=range("A" & i+1)
          bunion=true
      end if
    end if
Next

rng.Resize(, 2) = vData
runion.entirerow.delete
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜