
So I decided to test another assumption of mine: that Len is the fastest method for checking the length of a string, and therefore if a string variable is empty. The next series of posts will explore that in more detail.
My assumption of course is that Len is the best method, but I've never actually tested that. From what I have read, the length of a string is immediately available as part of the metadata for a string variable. I can't locate a source for that, so if anyone out there can, please let me know. I wrote a simple non-scientific procedure to compare Len with a loop procedure to see which runs faster.
The Test Procedure
The following procedure uses two loops:
- a loop using Len to calculate string length
- a Do loop to measure the string's length
Sub TestLen()
Dim i As Long, j As Long, k As Long
Dim str1 As String
Dim starttimeLen As Single
Dim endtimeLen As Single
Dim starttimeLoop As Single
Dim endtimeLoop As Single
Dim msg As String
Dim letterCount As Long
Dim nextchar As String
Const numberOfLoops As Long = 100000
str1 = "Hello World"
' use Len
starttimeLen = Timer
For i = 1 To numberOfLoops
letterCount = Len(str1)
Next i
endtimeLen = Timer
' count loop
starttimeLoop = Timer
For i = 1 To numberOfLoops
Do
j = j + 1
nextchar = Mid$(str1, j, 1)
If nextchar <> "" Then letterCount = letterCount + 1
Loop While nextchar <> ""
Next i
endtimeLoop = Timer
msg = "Number of iterations: " & numberOfLoops & vbCrLf
msg = msg & "Using Len: " & _
Format(endtimeLen - starttimeLen, "#.###") & " seconds" & vbCrLf
msg = msg & "Using Loop: " & _
Format(endtimeLoop - starttimeLoop, "#.###") & " seconds"
MsgBox msg
End Sub
I had to get creative to avoid using Len as the loop control in the second loop!
Results
At 100,000 iterations of each loop, there is little to no difference between each.
Even at 1,000,000 iterations, we don't see much difference between both loops. The Do loop seems to be keeping pace with Len.
At 10,000,000 iterations we're starting to see a major difference. All those Do loops are starting to add up to a full two second delay.
Finally, at 100 million loop iterations, there is simply no comparison. The Do loop's speed has slowed to a crawl while Len has barely broken a sweat.
Conclusion
With a low number of iterations, both loops perform at similar levels. When you have lots of iterations, however, the speed benefits of Len are clear. I suppose there are better ways to write the second loop (let me know), but it was the only way I could think of that avoided using Len as a loop control, which would have guaranteed a slower time. The second loop uses a Mid function call, an If-Then statement and a string comparison (which itself is the subject of the next post) which at least partially explains why it is slower.
I will be sticking with Len as it is simpler and already my habit.
To all my readers: Have a happy and safe holiday, see you next week!
Using the function len made me think of this optimization website:
http://www.shamrock-software.eu/vb.htm
It was saying you can use LenB which is even faster than Len and that not using a comparator (for simple if statements) is faster. For example,
But one has to be careful, since something like this (multiple arguments in an if statement) will give wrong results:
This is good information, but I'm not convinced it answers the second part of your assumption – that Len is the best way to check if a string variable is empty. That would be a special case, I think, and might have different results.
I'm still drinking my morning coffee, so I might not be thinking clearly yet. But why would checking for Len(str1)=0 be better than checking for str1=""?
Merry Christmas!
Hey JP,
I think using a for next is slightly faster then doing a loop although len is still faster. However in you code, I think resetting j back to 0 is the way to go and then do a double check to make sure the characters counted are the same using both procedures. Currently if j keeps growing then it seems it is not counting the text correctly. Maybe I am confused but think this matters. Below I altered your code to include my thoughts and then I included my alternate for next. Anyways this was fun to play with! Looking forward to hearing your thoughts!
Dave
Sub TestLen_for_next() Dim i As Long, j As Long, k As Long Dim str1 As String Dim starttimeLen As Single Dim endtimeLen As Single Dim starttimeLoop As Single Dim endtimeLoop As Single Dim msg As String Dim letterCountlen As Long Dim letterCountloop As Long Dim nextchar As String Dim jj As Integer Const numberOfLoops As Long = 1000000 str1 = "Hello World" ' use Len starttimeLen = Timer For i = 1 To numberOfLoops letterCountlen = letterCountlen + Len(str1) Next i endtimeLen = Timer ' count loop starttimeLoop = Timer For i = 1 To numberOfLoops For jj = 1 To 5000 nextchar = Mid$(str1, jj, 1) If nextchar = "" Then letterCountloop = letterCountloop + 1 Else GoTo 100 End If Next 100 Next i endtimeLoop = Timer msg = "Number of iterations: " & numberOfLoops & vbCrLf msg = msg & "Using Len: " & _ Format(endtimeLen - starttimeLen, "#.###") & " seconds" & vbCrLf msg = msg & "Using Loop: " & _ Format(endtimeLoop - starttimeLoop, "#.###") & " seconds" & vbCrLf msg = msg & "Using Len characters counted: " & letterCountlen & vbCrLf msg = msg & "Using Loop characters counted: " & letterCountloop MsgBox msg End Sub Sub TestLen_jp() Dim i As Long, j As Long, k As Long Dim str1 As String Dim starttimeLen As Single Dim endtimeLen As Single Dim starttimeLoop As Single Dim endtimeLoop As Single Dim msg As String Dim letterCountlen As Long Dim letterCountloop As Long Dim nextchar As String Const numberOfLoops As Long = 1000000 str1 = "Hello World" ' use Len starttimeLen = Timer For i = 1 To numberOfLoops letterCountlen = letterCountlen + Len(str1) Next i endtimeLen = Timer ' count loop starttimeLoop = Timer For i = 1 To numberOfLoops j = 0 Do j = j + 1 nextchar = Mid$(str1, j, 1) If nextchar = "" Then letterCountloop = letterCountloop + 1 Loop While nextchar = "" Next i endtimeLoop = Timer msg = "Number of iterations: " & numberOfLoops & vbCrLf msg = msg & "Using Len: " & _ Format(endtimeLen - starttimeLen, "#.###") & " seconds" & vbCrLf msg = msg & "Using Loop: " & _ Format(endtimeLoop - starttimeLoop, "#.###") & " seconds" & vbCrLf msg = msg & "Using Len characters counted: " & letterCountlen & vbCrLf msg = msg & "Using Loop characters counted: " & letterCountloop MsgBox msg End Sub