Reputation: 171
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)
Upvotes: 15
Views: 11514
Reputation: 3346
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)
Upvotes: 5
Reputation: 1124928
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.
Upvotes: 13