2

I'm having an issue with my Python code, but that's something I had already encountered in other languages and I'd like to have a general answer.

Let's say I have a loop containing many statements. One of these statements depends on a condition that does not change over the iterations. I see two ways to implement this:

for ... : 
    ... #many statements
    if conditionA :
        statementA
    elif conditionB : 
        statementB
    else 
        statementC

or :

if conditionA :
    for ... : 
        ... #many statements
        statementA
elif conditionB : 
    for ... : 
        ... #many statements
        statementB
else :
    for ... :
        ... #many statements
        statementC

In the first solution, the problem is that we test something at each iteration, which isn't necessary. The second solution has a better speed because it just tests the condition once and then starts the loop accordingly, which is what I want to do ; but now there is a lot of code duplication (many statements rewritten everytime...).

Is there a third way I haven't thought of that would be as efficient as the second one but without code duplication? Thanks!

EDIT :

I read on a similar topic (Optimizing a Loop vs Code Duplication) that C++ compilers already do the optimization (by transforming the first version into the second one during compilation). What about interpreted languages such as Python?

Community
  • 1
  • 1
Telergoel
  • 353
  • 1
  • 13
  • Are your conditions significantly onerous to test? if so, you could assign their results to variables to avoid having to test them repeatedly inside your loop. – khelwood Feb 28 '17 at 09:36
  • Can't you compute a value of `conditionA` and `conditionB` before a loop? – Łukasz Rogalski Feb 28 '17 at 09:36
  • Unless your condition is not O(1), *time complexity* is the same whether the loop is inside the conditions or the other way around. Most likely you're misusing it for just "speed". – spectras Feb 28 '17 at 09:41
  • Precomputing the conditions is a first piece of answer indeed ! The thing is my loop will iterate over a very large database and I wonder how much total time the 'if' statement can cost if I use it at each iteration, even with a very simple condition to test. Maybe it's insignificant ? – Telergoel Feb 28 '17 at 09:42
  • @spectras I was misusing the term "time complexity" indeed, I meant speed ! – Telergoel Feb 28 '17 at 09:43
  • Depending on the condition it might be possible to use a dictionary as a despatch table. The key would be the thing being tested and the value would be the name of a function containing the condition code. Of course that is not viable if the condition is complex. That can remove the `if` and `elif` statements all together, except a sanity check for the presence of the key. – cdarke Feb 28 '17 at 09:45
  • The first version is more readable and better maintainable. With pre-computed conditions stored as simple boolean flags and tests ordered from the most common condition (if there is such thing) I don't think it can be improved. – VPfB Feb 28 '17 at 10:01
  • @cdarke a dictionary would still have to test the value of the key just like an 'if' statement, wouldn't it? Or I didn't understand you well and I'd need an example :3 – Telergoel Feb 28 '17 at 10:02
  • @VPfB thanks ! I agree with you. Then the implicit question is: how much time does the 'if' statement cost? Must be negligible with such simple conditions. – Telergoel Feb 28 '17 at 10:05
  • @Telergoel You can timeit to be sure (https://docs.python.org/3.5/library/timeit.html). – VPfB Feb 28 '17 at 10:09

1 Answers1

0

What my code below does is separate the conditions which 'depend' on the loop element and the ones that are 'independent' of the loop element.

Make a loop function that takes a lambda instead as your statement. The only duplication here might be the lambda part I guess

def loop(arr,func):
     for a in arr
        // many statements

        func(a)
        //statement for that particular condition using lambda


if condition A: ## assume condition doesn't depend on loop elements
    loop(arr,lambda x:##any action)

elif condition B:
    loop(arr,lambda x:##any action)
.
.
.

else:
    for el in arr:
        //many statements

        if condition X: ## This condition depends on the loop element!..
            //statement X
        elif condition Y:
            //statement Y 
        .
        .
        .

I wanted to even minimize this double duplication but that would get rather complex as you'd need conditional lambdas and stuff.

EDIT:

Do this in the 'else' in my code above:

else:
    def func2(a):
        if condition A:
            // some statement depending on the element. 'a' in this case
        elif condition B:
            // some statement depending on the element

    loop(arr,func2)

Now, even the double duplication is reduced :-D

Abhishek J
  • 2,386
  • 2
  • 21
  • 22
  • It's interesting ! I wouldn't even need the last part with condition X and Y in my case. Thanks for the answer :) – Telergoel Feb 28 '17 at 10:17