Search code examples
pythonfor-loopcomparisoniterationlist-comparison

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


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)  

Solution

  • When you have three or more numbered and similarly-used variables, think lists.

    With that in mind, we first change list1, list2, list3, ... into a list of lists (indexed 0,1,2,3 instead of 1,2,3,4). Except don't call it list, because that's a useful name for something that's already useful. lst is pretty popular in Python. I'm also going to change list5 into lstA and list6 into lstB because 5 and 6 no longer make sense.

    Now we have this:

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

    Now it's more obvious that we're basically doing the same thing four times.


    When you have to do the same thing a bunch of times, think loops.

    We'll change the blocks into loops. We'll also use a flag variable to keep track of whether something failed while testing our logic, and use the logic "if it does not work, skip stuff" rather than "if it works, do stuff"

    for H in range(0,len(a_list)):
        if a_list[H] > lst[3][0]:
            continue #reducing indent levels by negating the check:
                     #quit on failure instead of work on success
    
        lstA = [number_list[i]]
    
        quit = False
    
        for j in range(4):
            if function(lst[j],lstA) != lst[j][1]: #testing FALSEHOOD
                quit = True
                break #the j loop only
    
        if quit:
            continue #reducing indent levels by negating the check
    
        lstA.append(input('some input from the user'))
        other_function(lstA)
        if lstA[1]== 40:
            print ('something something')
            break #out of EVERY loop
        #else: #don't need the else because we broke
    
        for H in range(0,len(a_list)):
            if not a_list[H] > lstA[0]:
                continue #reducing indent levels by negating the check
    
            lstB = [number_list[i]]
    
            for j in range(4):
                if function(lst[j],lstB) != lst[j][1]: #testing FALSEHOOD
                    quit = True;
                    break #to the H loop
            if not quit and  function(lstA,lstB)== lstA[1]: #combining two checks
                lstB.append(input('some input from theuser'))
                other_function(lstB)
                if lstB[1]== 40:
                    print ('something something')
                    break #out of EVERY loop
                else: #at this point I'm lost and can't refactor
                    etc. (one extra comparison every time)  
    

    When you have to break out of multiple loops at once, think functions and returning instead of breaking. Or exceptions and try blocks, but some might find that distasteful.

    The failure flag works, but isn't very elegant. There's an exaggerated saying: "... if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program." Read this as: If you have a lot of levels of indentation (and some languages require more than others), you should think about whether you can move some of the logic into a function.

    We'll also move some repeated logic into a checker function.

    (Finally, I think it's a bug that your second for-loop is nested in your first. Since they have the same iterator variable H, I think that would cause an infinite loop. So I fixed that.)

    #returns FALSE if a check fails, unlike the `quit` variable
    def checker(lst, lstA):
        for i in range(4):
            if function(lst[i],lstA) != lst[i][1]: #testing FALSEHOOD
                return False;
        return True;
    
    
    def main(???):
        for H in range(0,len(a_list)):
            if a_list[H] > lst[3][0]:
                continue
    
            lstA = [number_list[i]]
    
            if not checker(lst,lstA):
                continue
    
            lstA.append(input('some input from the user'))
            other_function(lstA)
            if lstA[1]== 40:
                print ('something something')
                return #break out of EVERY loop
    
        for H in range(0,len(a_list)):
            if not a_list[H] > lstA[0]:
                continue
    
            lstB = [number_list[i]]
    
            if checker(lst,lstB) and  function(lstA,lstB) == lstA[1]:
                lstB.append(input('some input from theuser'))
                other_function(lstB)
                if lstB[1]== 40:
                    print ('something something')
                    return # break out of EVERY loop
                else: #at this point I'm lost and can't refactor
                    etc. (one extra comparison every time)