Trimming cells, before and after


September 16, 2008 – 10:16 am by JP

    As an experiment, I decided to rewrite one of my old routines that I use a lot, but hadn’t re-thought in a while — a simple sub that trims worksheet cells. I plan to do that more often in the coming weeks, because a lot of my code is old and written quick and dirty to get something done, sometimes by brute force.

    I get a lot of poorly formatted worksheets, and as you know, if a cell contains hidden spaces at the end, then string comparisons (i.e. “=IF(A1=B1)”) will fail. This is maddening at times, so originally I wrote this routine:


Sub Trim_Cells()
Dim cell As Excel.Range

If Selection.Cells.Count > 1 Then
    Selection.SpecialCells(xlCellTypeConstants).Select
End If

With WorksheetFunction
    For Each cell In Selection
        cell = Trim(cell)
        cell = .Trim(cell)
    Next cell
End With

ActiveCell.Select
End Sub

    With a shortcut key or toolbar button, it’s very convenient. And as you might be able to tell by looking at it, very slow. To speed it up somewhat, it limits the action cells to just constants, but the VBA code still has to hit the worksheet in a 1:2 ratio (!) for each cell in the selection, because for good measure I called the VBA Trim function as well as the Worksheetfunction version. That means each cell has to be hit twice!

    I inserted the code above into a generic Timer sub I use to for testing purposes, and ran it on a range of 500 cells. See below for test results.


Sub TimerTest()
'
' place your test code between the starttime and endtime variables
'
StartTime = Timer
'
Dim cell As Excel.Range

If Selection.Cells.Count > 1 Then
    Selection.SpecialCells(xlCellTypeConstants).Select
End If

With WorksheetFunction
    For Each cell In Selection
        cell = Trim(cell)
        cell = .Trim(cell)
    Next cell
End With

ActiveCell.Select
'
EndTime = Timer
MsgBox ("This routine took " & (EndTime - StartTime) & " seconds.")
'
'
'
End Sub

    As you can see, this is barely tolerable. In a large worksheet, unacceptable. So on a lark I rewrote the code to use arrays exclusively. Here it is:


Sub Trim_Cells_Array_Method()

Dim arrData() As Variant
Dim arrReturnData() As Variant
Dim rng As Excel.Range
Dim lRows As Long
Dim lCols As Long
Dim i As Long, j As Long

lRows = Selection.Rows.Count
lCols = Selection.Columns.Count

ReDim arrData(1 To lRows, 1 To lCols)
ReDim arrReturnData(1 To lRows, 1 To lCols)

Set rng = Selection
arrData = rng.Value

For j = 1 To lCols
  For i = 1 To lRows
    arrReturnData(i, j) = Trim(arrData(i, j))
  Next i
Next j

rng.Value = arrReturnData

Set rng = Nothing
End Sub

    When this code is plugged into the TimerTest sub, here is the result:

    By using arrays and limiting the number of hits on the worksheet (i.e. limiting the interaction between Excel and VBA), we are able to produce a 1,000,000% increase in speed! Seriously, the lesson I’ve learned here is:

a) Read all your worksheet data into an array up front, try to manipulate it in VBA exclusively (no Worksheetfunction calls or temporary worksheets), and dump it back to the worksheet in one shot. Your watch will thank you.
a) Loops aren’t intrinsically bad. It’s the loops that require repeated hits on the worksheet (especially 1:1 ratio ‘For Each x in Selection’ type loops) that are costly. As I’ve mentioned before, when VBA and Excel have to interact, there is a time penalty.

Enjoy,
JP


If you enjoyed this page, share it!
    StumbleUpon Technorati Digg Google del.icio.us MisterWong TwitThis

Print This Post Print This Post  |  Email This Post Email This Post  |  rss Subscribe to Posts Feed  |  rss Subscribe to Comments

Filed Under: Excel, VBA, arrays
Tags: ,

  1. 3 Responses to “Trimming cells, before and after”:

  2. Between the timer statements and your code, insert these statements:

    Application.ScreenUpdating = False ‘ beginning

    Application.ScreenUpdating = True ‘ end

    I’ll bet this comes in closer to the array approach than the original worksheet approach.

    By Jon Peltier on Sep 16, 2008

  3. Well met, Jon!

    I added the ScreenUpdating option and here was the result:

    Old way: .125 seconds
    New way: .01 seconds

    I also added ‘Calculation = xlCalculationManual’ and got even more improvement from the original method:

    Old way: .11 seconds
    New way: .01 seconds

    There was an additional slight improvement when calculation was turned off as well. The array method wasn’t really helped by turning calculation off, though; my guess is because the worksheet isn’t being touched that much in the first place, so not much recalculation was taking place anyway.

    Thx,
    JP

    By JP on Sep 17, 2008

  4. The array technique should be touching the worksheet twice, once to read and once to write, and reading is much faster than writing. The looping technique is more interactive, with one read and write per cell. Turning off Screen Updating and Caluclation will have a large effect on the loop, since these make each of many I/O operation faster. In the array, these steps make each of one operation faster.

    By Jon Peltier on Sep 17, 2008

Post a Comment


Certain comments are subject to moderation and may not appear immediately. First-time comments are moderated. You can use HTML tags in your comment. If you include a greater-than or less-than sign or anything else that could be interpreted as HTML, you need to escape those characters. To post VBA code in your comment, use [VBA] tags, like this: [VBA]Code goes here[/VBA].





Subscribe without commenting

Keep Reading:

Browse Posts:


« Excel games || Excel Class Scheduler »