2

In VBA, which of the following if statements will perform better?

Context: I'm iterating through a sheet looking for an entry.

if [condition1] and [condition2] and [condition3] then
    *do something*
end if

or

if [condition1] then
    if [condition2] then
        if [condition3] then
            *do something*
        end if
    end if
end if

My intuition says the second statement, as it only needs to check one initial condition before proceeding to the next iteration, but is this so? Also, is there a better way of doing this?

Cornel Verster
  • 1,664
  • 3
  • 27
  • 55
  • 7
    *will perform better* - you can actually test this yourself by wrapping a timer around both statements and testing performance against actual code :). Other than that, this question is way to vague, given the psuedo-code, to really be of help with. – Scott Holtzman Oct 10 '17 at 12:52
  • 1
    AFAIK, first statement will evaluate all 3 conditions even if first is false. Second statement should therefore be faster. Anyway this question should be on CodeReview, rather than SO. – iDevlop Oct 10 '17 at 12:55
  • 5
    Just being picky, but the first statement isn't valid VBA. – Enigmativity Oct 10 '17 at 12:56
  • 1
    I would expect that there is, in practical terms, no difference between the two. The Excel app would take many orders of magnitude more time to process its code than the VBA code would take to evaluate an `If`. – Enigmativity Oct 10 '17 at 12:59
  • Taking your context into account `FIND` would be a faster method. – Darren Bartrup-Cook Oct 10 '17 at 13:04
  • 1
    There are faster ways than iterating to search or .Find method, [this link](https://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/) compares 3 methods. And the conclusion is that using Arrays is the best method. – danieltakeshi Oct 10 '17 at 13:39
  • 1
    @PatrickHonorez hypothetical pseudo-code that's just in the post for illustrative purposes (as well as [mcve]'s), has nothing to do with [codereview.se] and this particular question would get slammed-shut within minutes. Please read [a guide to CR for SO users](https://codereview.meta.stackexchange.com/q/5777/23788) before making your next CR recommendation. – Mathieu Guindon Oct 10 '17 at 14:06
  • Because this wasn't the question asked, I think it should be pointed out that there is more important consideration here: which will run without errors when conditions themselves can cause errors? The first would evaluate all conditions and thus generate a runtime error that would have been avoided with the 2nd option. That would be a more compelling argument for writing code differently than simply just performance. – this Dec 01 '17 at 15:28

3 Answers3

8

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

— Donald Knuth

Assuming none of the conditions have side-effects and essentially boil down to this:

If True And True And False Then

Then you're over-thinking it and are likely over-optimizing without any meaningful performance gains. Stop trying to squeeze out every nanosecond from your code, and write code that's easy to read, maintain, debug, and extend instead: if there's a performance bottleneck anywhere in your code, it's not here.


Context: I'm iterating through a sheet looking for an entry.

See, iterating through a sheet looking for an entry is your bottleneck. Interacting with a worksheet is hundreds if not thousands of times slower than interacting with an in-memory array.

So yes, because you're writing expensive code, lack of short-circuiting will make a difference, but not because short-circuiting is more a efficient use of Boolean logic - it will make a [potentially significant] difference because you'll be conditionally avoiding expensive worksheet reads.

If that sounds contradictory, you're not getting my point: the performance impact of short-circuiting Boolean logic on code that's already efficient, is largely insignificant.

Go on, try dumping the Range you're iterating (and are you doing that with a For or a For Each loop? There's a massive difference between the two, depending on what you're doing) into a 2D array, and then use a For loop to iterate it and look for your entry. I promise a much more noticeable performance improvement than anything you could get out of splitting your conditionals to simulate short-circuiting.

Or, perhaps re-evaluate whether you need to iterate anything at all. If you're looking for an entry, and depending on what your data looks like, you could combine the "condition columns" into one and use Application.WorksheetFunction.Match to locate an entry without writing any loops or conditions.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
  • Hi, thank you very much for the in-depth answer. When you say "combine the conditions columns into one" do you mean do a concatenate on them? I'm just wondering if it would work as I'm still looking for a specific term / value within a cell using Match right? So even if I join my condition fields, how would I use Match to find the joined term / value in the sheet? – Cornel Verster Oct 11 '17 at 15:31
  • Yes, you concatenate them. Then you concatenate your lookup value the same way and match it. Same as any multi-column vlookup.. – Mathieu Guindon Oct 11 '17 at 15:33
  • 1
    I understand, I guess I can add the concatenated version in a hidden column on the side or something as a kind of unique identifier. Thanks for the help! – Cornel Verster Oct 11 '17 at 15:35
7

Here's link that might be helpful.

Generally, second would perform faster for simple reason: if first condition fails, it won't check other two. In first approach it has to evaluate all three conditions. In other programming languages you have short-circuiting, which you implemented in second approach (in VBA it has to be done this way, since there's no short-circuiting).

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
1

The 2nd format would be the faster implementation.

You can see that vba does not short circuit evaluations by trying the following commands in the immediate window:

if 1=0 and 1/0 then ?"Short Circuit"
if 1=1 or 1/0 then ?"Short Circuit"

If vba operated like some other languages, then you would get the message Short Circuit printed. Instead, you get the error:
enter image description here

Of course, I would refer you to Mat's Mug's answer, as reading a range into memory operates a lot faster than reading a sheet directly.

I will refer you to my answer to another question on how to read/write arrays and cells

SeanC
  • 15,695
  • 5
  • 45
  • 66