Python - Any way to avoid several if-statements inside each other in a for-loop?

user2966098 picture user2966098 · Dec 5, 2013 · Viewed 9.9k times · Source

I need a better way to do this. I'm new with programming but I know that this is a very inefficient way of doing it and that I need a function for this, I just don't know how to do it exactly. any suggestions? I'm VERY grateful for any help!

for H in range(0,len(a_list)):
    if a_list[H] > list4[0]:
        list5 = [number_list[i]]
        if function(list1,list5) == list1[1]:
            if function(list2,list5)== list2[1]:
                if function(list3,list5)== list3[1]:
                    if function(list4,list5)== list4[1]:
                        list5.append(input('some input from the user'))
                        other_function(list5)
                        if list5[1]== 40:
                            print ('something something')
                            break out of EVERY loop 
                         else: 
                            for H in range(0,len(a_list)):
                                if a_list[H] > list5[0]:
                                    list6 = [number_list[i]]
                                    if function(list1,list6) == list1[1]:
                                        if function(list2,list6)== list2[1]:
                                            if function(list3,list6)== list3[1]:
                                               if function(list4,list6)== list4[1]:
                                                  if function(list5,list6)== list5[1]:
                                                     list6.append(input('some input from theuser'))
                                                     other_function(list6)
                                                         if list6[1]== 40:
                                                             print ('something something')
                                                                 break out of EVERY loop 
                                                         else: 
                                                            etc. (one extra comparison every time)  

Answer

Martijn Pieters picture Martijn Pieters · Dec 5, 2013

Use the all() function to test multiple related conditions:

if all(function(lst, list5) == lst[1] for lst in (list1, list2, list3, list4)):

and

if all(function(lst, list6) == lst[1] for lst in (list1, list2, list3, list4, list5)):

Like the nested if statements, all() will short-circuit; return False as soon as any of the tests fails.

In addition, loop over lists directly, instead of generating a range of indices. If you are using break, you don't need to use else either, removing another level of indentation.

You can remove another level by filtering a_list:

for H in filter(lambda H: H > list4[0], a_list):

Together, this reduces your nesting to:

for H in filter(lambda H: H > list4[0], a_list):
    list5 = [number_list[i]]
    if all(function(lst, list5) == lst[1] for lst in (list1, list2, list3, list4)):
        list5.append(input('some input from the user'))
        other_function(list5)
        if list5[1]== 40:
            print ('something something')
            break # out of EVERY loop 

        for J in filter(lambda J: J >list5[0], a_list):
            if all(function(lst, list6) == lst[1] for lst in (list1, list2, list3, list4, list5)):
            list6.append(input('some input from theuser'))
            other_function(list6)
            if list6[1]== 40:
                print ('something something')
                break # out of EVERY loop 

            # continue here

Presumably your break statements actual use exceptions (raise CustomException() and try:, except CustomException: # break out of all the loops fast), as a regular break would only stop the current loop.

If you are continuously adding further lists and nesting, you probably want use a list to hold all those nested lists, then simply add to the outer list:

class EndLoops(Exception): pass

stack = [[number_list[0]]]
try:
    for i in number_list[1:]:
        for H in filter(lambda H: H > stack[-1][0], a_list):
            stack.append([i])
            if all(function(lst, stack[-1]) == lst[1] for lst in stack[:-1]):
                stack[-1].append(input('some input from the user'))
                other_function(stack[-1])
                if stack[-1][1] == 40:
                    print ('something something')
                    raise EndLoops
except EndLoops:
    pass # broken out of outer loop

and suddenly all the nesting has gone; instead you moved the nesting to a stack list of lists.

Note that I don't know what the outer-most loop looks like in your code, I just took an educated stab in the dark at it, but the idea should be roughly correct.