How to continue in nested loops in Python - python

How can you continue the parent loop of say two nested loops in Python?
for a in b:
for c in d:
for e in f:
if somecondition:
<continue the for a in b loop?>
I know you can avoid this in the majority of cases but can it be done in Python?

Break from the inner loop (if there's nothing else after it)
Put the outer loop's body in a function and return from the function
Raise an exception and catch it at the outer level
Set a flag, break from the inner loop and test it at an outer level.
Refactor the code so you no longer have to do this.
I would go with 5 every time.

Here's a bunch of hacky ways to do it:
Create a local function
for a in b:
def doWork():
for c in d:
for e in f:
if somecondition:
return # <continue the for a in b loop?>
doWork()
A better option would be to move doWork somewhere else and pass its state as arguments.
Use an exception
class StopLookingForThings(Exception): pass
for a in b:
try:
for c in d:
for e in f:
if somecondition:
raise StopLookingForThings()
except StopLookingForThings:
pass

You use break to break out of the inner loop and continue with the parent
for a in b:
for c in d:
if somecondition:
break # go back to parent loop

from itertools import product
for a in b:
for c, e in product(d, f):
if somecondition:
break

use a boolean flag
problem = False
for a in b:
for c in d:
if problem:
continue
for e in f:
if somecondition:
problem = True

Looking at All the answers here its all different from how i do it\n
Mission:continue to while loop if the if condition is true in nested loop
chars = 'loop|ing'
x,i=10,0
while x>i:
jump = False
for a in chars:
if(a = '|'): jump = True
if(jump==True): continue

lista = ["hello1", "hello2" , "world"]
for index,word in enumerate(lista):
found = False
for i in range(1,3):
if word == "hello"+str(i):
found = True
break
print(index)
if found == True:
continue
if word == "world":
continue
print(index)
Now what's printed :
>> 1
>> 2
>> 2
This means that the word no.1 ( index = 0 ) appeard first (there's no way for something to be printed before the continue statement). The word no.2 ( index = 1 ) appeared second ( the word "hello1" managed to be printed but not the rest ) and the word no.3 appeard third what mean's that the words "hello1" and "hello2" managed to be printed before the for loop reached this said third word.
To sum up it's just using the found = False / True boolean and the break statement.
Hope it helps!

#infinite wait till all items obtained
while True:
time.sleep(0.5)
for item in entries:
if self.results.get(item,None) is None:
print(f"waiting for {item} to be obtained")
break #continue outer loop
else:
break
#continue
I wish there could be a labeled loop ...

Related

Is there an “elif” equivalent in for/else statements

In if/elif/else statements, elifs are checked if the if is false, and if both the if and elifs are false then the else is run.
For loops have something similar with the else keyword - if the loop doesn’t encounter a break, then the code inside else is run.
So, for loops have an else equivalent to if/elif/else statements. My question is however, is there an equivalent to elif.
I’m thinking that it would be something along the lines of:
Run for loop. If no break is encountered, go onto the next
specified loop
Run the specified for loop, if no break is encountered, go onto the
next.
Repeat until no more loops are left, and if no breaks have been
encountered up to this point, run the else.
I’m aware you can emulate this effect. Just as you can do this with if/else statements to emulate the elif:
if condition:
do_something()
else:
if another_condition:
do_something_else()
else:
default()
you can do this with for loops:
for x in y:
if condition:
break
else:
for n in m:
if another_condition:
break
else:
default()
While the above code is valid, like with if/else statements, it’s faily ugly and I was hoping to find a better alternative.
No. If you look at the grammar of the for statement:
for_stmt:
| 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]
. . .
It ends in an optional else_block, but nothing else. Your emulation is as good as you'll get I believe.
What if you make the variable that determins whether you should continue global? Since if any of the conditions are met, you don't want to continue with any of the following loops this should work:
def do_something():
for i in range(3):
condition = i < 3
if not condition:
return False
return True
def do_something_else():
for i in range(3):
condition = i < 2
if not condition:
return False
return True
condition_met = True
if condition_met:
print('we start here')
condition_met = do_something()
if condition_met:
print('and should get here')
condition_met = do_something_else()
if condition_met:
print('but not here')
It may not be amazing, but at least it's not nested, and sort of looks like the syntax you're looking for.
You could also use a while loop:
operations = [do_something, do_something_else]
i = 0
while condition_met and i < len(operations):
condition_met = operations[i]()
While the for-loop syntax doesn't allow this (as shown by #Carcigenicate), you can keep nesting levels down by using a try-else:
try:
for x in y:
if z:
raise SomeException
for m in n:
if o:
raise SomeException
except SomeException:
pass
else:
default()
A cleaner way, however, might wrap the loops in functions:
# these can be more complex non-anonymous functions
f1 = lambda: any(1 for x in y if z)
f2 = lambda: any(1 for m in n if o)
f3 = ...
if not any(f() for f in (f1, f2, f3)):
default()
I'm not sure, but maybe while will be ok for you
i = 0
while i < 10:
if condition:
break
i += 1

Redo for loop iteration in Python

Does Python have anything in the fashion of a "redo" statement that exists in some languages?
(The "redo" statement is a statement that (just like "break" or "continue") affects looping behaviour - it jumps at the beginning of innermost loop and starts executing it again.)
No, Python doesn't have direct support for redo. One option would something faintly terrible involving nested loops like:
for x in mylist:
while True:
...
if shouldredo:
continue # continue becomes equivalent to redo
...
if shouldcontinue:
break # break now equivalent to continue on outer "real" loop
...
break # Terminate inner loop any time we don't redo
but this mean that breaking the outer loop is impossible within the "redo-able" block without resorting to exceptions, flag variables, or packaging the whole thing up as a function.
Alternatively, you use a straight while loop that replicates what for loops do for you, explicitly creating and advancing the iterator. It has its own issues (continue is effectively redo by default, you have to explicitly advance the iterator for a "real" continue), but they're not terrible (as long as you comment uses of continue to make it clear you intend redo vs. continue, to avoid confusing maintainers). To allow redo and the other loop operations, you'd do something like:
# Create guaranteed unique sentinel (can't use None since iterator might produce None)
sentinel = object()
iterobj = iter(mylist) # Explicitly get iterator from iterable (for does this implicitly)
x = next(iterobj, sentinel) # Get next object or sentinel
while x is not sentinel: # Keep going until we exhaust iterator
...
if shouldredo:
continue
...
if shouldcontinue:
x = next(iterobj, sentinel) # Explicitly advance loop for continue case
continue
...
if shouldbreak:
break
...
# Advance loop
x = next(iterobj, sentinel)
The above could also be done with a try/except StopIteration: instead of two-arg next with a sentinel, but wrapping the whole loop with it risks other sources of StopIteration being caught, and doing it at a limited scope properly for both inner and outer next calls would be extremely ugly (much worse than the sentinel based approach).
No, it doesn't. I would suggest using a while loop and resetting your check variable to the initial value.
count = 0
reset = 0
while count < 9:
print 'The count is:', count
if not someResetCondition:
count = count + 1
This is my solution using iterators:
class redo_iter(object):
def __init__(self, iterable):
self.__iterator = iter(iterable)
self.__started = False
self.__redo = False
self.__last = None
self.__redone = 0
def __iter__(self):
return self
def redo(self):
self.__redo = True
#property
def redone(self):
return self.__redone
def __next__(self):
if not (self.__started and self.__redo):
self.__started = True
self.__redone = 0
self.__last = next(self.__iterator)
else:
self.__redone += 1
self.__redo = False
return self.__last
# Display numbers 0-9.
# Display 0,3,6,9 doubled.
# After a series of equal numbers print --
iterator = redo_iter(range(10))
for i in iterator:
print(i)
if not iterator.redone and i % 3 == 0:
iterator.redo()
continue
print('---')
Needs explicit continue
redone is an extra feature
For Python2 use def next(self) instead of def __next__(self)
requires iterator to be defined before the loop
I just meet the same question when I study perl,and I find this page.
follow the book of perl:
my #words = qw(fred barney pebbles dino wilma betty);
my $error = 0;
my #words = qw(fred barney pebbles dino wilma betty);
my $error = 0;
foreach (#words){
print "Type the word '$_':";
chomp(my $try = <STDIN>);
if ($try ne $_){
print "Sorry - That's not right.\n\n";
$error++;
redo;
}
}
and how to achieve it on Python ??
follow the code:
tape_list=['a','b','c','d','e']
def check_tape(origin_tape):
errors=0
while True:
tape=raw_input("input %s:"%origin_tape)
if tape == origin_tape:
return errors
else:
print "your tape %s,you should tape %s"%(tape,origin_tape)
errors += 1
pass
all_error=0
for char in tape_list:
all_error += check_tape(char)
print "you input wrong time is:%s"%all_error
Python has not the "redo" syntax,but we can make a 'while' loop in some function until get what we want when we iter the list.
Not very sophiscated but easy to read, using a while and an increment at the end of the loop. So any continue in between will have the effect of a redo. Sample to redo every multiple of 3:
redo = True # To ends redo condition in this sample only
i = 0
while i<10:
print(i, end='')
if redo and i % 3 == 0:
redo = False # To not loop indifinively in this sample
continue # Redo
redo = True
i += 1
Result: 00123345667899
There is no redo in python.
A very understandable solution is as follow:
for x in mylist:
redo = True
while redo:
redo = False
If should_redo:
redo = True
It's clear enough to do not add comments
Continue will work as if it was in the for loop
But break is not useable, this solution make break useable but the code is less clear.
Here is a solution for python 3.8+ since now we have the := operator:
for key in mandatory_attributes: # example with a dictionary
while not (value := input(f"{key} (mandatory): ")):
print("You must enter a value")
mandatory_attributes[key] = value

Python Continue inside nested loops, getting to the right level of the nesting

I am working on something that needs to make it's way through several levels of checking if conditions are met before either exiting all together or setting certain variables and then starting the loop over. My question revolves around how to jump back to the primary while loop from the internal for loop.
while True:
message = stomp.get
message = simplejson.loads(message.body)
if message[0]['fieldname1'] == False:
global ShutdownState
ShutdownState = True
break # Should leave the While loop all together
else:
for item in message[0]['fieldname2'][0]['fieldname2-1']
if item['fieldname2-1-1'] == True:
list1_new[len(list_new):] = [item['fieldname2-1-2']
list1-state = set(list1) == set(list1_new)
if list1-state == True:
continue # should reset the while loop
else:
list1 = list1_new # should print the new list1 and then reset the while loop
print list1
continue
It's not clear whether the sample code was meant to be representative of your whole loop, or just the beginning of it. If it was the whole thing, then there are lots of ways you can restructure it. Here's a first stab (note that are some typos in the code (e.g., list1-state rather than list1_state, and things like that), so I've had to adjust some things. You'll need to check whether it still matches up with your original code. (For more about this implementation of finding the first element in the list, and some alternatives, have a look at Python: Find in list.)
while True:
message = stomp.get
message = simplejson.loads(message.body)
# If the message doesn't match this criterion,
# we need to abort everything.
if not message[0]['fieldname1']:
global ShutdownState
ShutdownState = True
break
try:
# get the first item in message[0]['fieldname2'][0]['fieldname2-1']
# such item['fieldname2-1-1'] is true. Whether we
# find one and do this code, or don't and catch the
# StopIteration, we wrap back to the while loop.
item = next(x
for x in message[0]['fieldname2'][0]['fieldname2-1']
if item['fieldname2-1-1'])
list1_new[len(list_new),:] = item['fieldname2-1-2']
list1_state = (set(list1) == set(list1_new))
if not list1_state:
list1 = list1_new # should print the new list1 and then reset the while loop
print list1
except StopIteration:
# There was no such item.
pass
You might also clean this up by making it a do-while loop, but that's a less major factor. Based on Emulate a do-while loop in Python?, you could do something like:
def get_message():
message = stomp.get
return simplejson.loads(message.body)
message = get_message()
while message[0]['fieldname1']:
try:
# get the first item in message[0]['fieldname2'][0]['fieldname2-1']
# such item['fieldname2-1-1'] is true. Whether we
# find one and do this code, or don't and catch the
# StopIteration, we wrap back to the while loop.
item = next(x
for x in message[0]['fieldname2'][0]['fieldname2-1']
if item['fieldname2-1-1'])
list1_new[len(list_new),:] = item['fieldname2-1-2']
list1_state = (set(list1) == set(list1_new))
if not list1_state:
list1 = list1_new # should print the new list1 and then reset the while loop
print list1
except StopIteration:
# There was no such item.
pass
message = get_message()
global ShutdownState
ShutdownState = True

Start a new iteration of a loop from a different function in the loop [python]

How do you go about starting the next i without using continue or break?
def function_in_main():
if #something happens:
#start new next iteration for the loop in the main function
def main():
n = 1
for i in range(len(alist)):
print ('step ', n)
function_in_main()
n += 1
main()
Output should look somewhat like:
step 1
#if or until something happens
step 2
etc
Just make function_in_main return when your if statement is true. when it returns, the loop will move on to the next iteration and then re-call function_in_main.
Maybe try raising an exception:
def function_in_main():
if #something happens:
raise Exception
def main():
n = 1
for i in range(len(alist)):
print ('step ', n)
try:
x()
except Exception:
continue
n += 1
main()
You can specify or make whatever type of exception you want.
Here is an example:
def function_in_main(x):
return x=='Whopee' # will return True if equal else False
def main():
alist=['1','ready','Whopee']
for i,item in enumerate(alist, 1):
print ('step {}, item: "{}" and {}'.format(i,item,function_in_main(item)))
main()
Prints:
step 1, item: "1" and False
step 2, item: "ready" and False
step 3, item: "Whopee" and True
Note the use of enumerate rather than manually keeping a counter.
Sure you're not thinking of a while loop or something? It's a little tough to see what you're getting at…
def your_function():
#…do some work, do something to something else
if something_is_true:
return True
else:
return False
def main():
condition = True
for i in range(len(your_list)):
while condition:
print "Step: %d" % i
your_function()
Only when your_function returns False will the loop in main continue, otherwise it will stay within the while loop.

Python: is there a C-like for loop available?

Can I do something like this in Python?
for (i = 0; i < 10; i++):
if someCondition:
i+=1
print i
I need to be able to skip some values based on a condition
EDIT: All the solutions so far suggest pruning the initial range in one way or another, based on an already known condition. This is not useful for me, so let me explain what I want to do.
I want to manually (i.e. no getopt) parse some cmd line args, where each 'keyword' has a certain number of parameters, something like this:
for i in range(0,len(argv)):
arg = argv[i]
if arg == '--flag1':
opt1 = argv[i+1]
i+=1
continue
if arg == '--anotherFlag':
optX = argv[i+1]
optY = argv[i+2]
optZ = argv[i+3]
i+=3
continue
...
Yes, this is how I would do it
>>> for i in xrange(0, 10):
... if i == 4:
... continue
... print i,
...
0 1 2 3 5 6 7 8 9
EDIT
Based on the update to your original question... I would suggest you take a look at optparse
for (i = 0; i < 10; i++)
if someCondition:
i+=1
print i
In python would be written as
i = 0
while i < 10
if someCondition
i += 1
print i
i += 1
there you go, that is how to write a c for loop in python.
There are two things you could do to solve your problem:
require comma-separated arguments which are going to be grouped into the following option value, you could use getopt, or any other module then.
or do more fragile own processing:
sys.argv.pop()
cmd = {}
while sys.argv:
arg = sys.argv.pop(0)
if arg == '--arg1':
cmd[arg] = sys.argv.pop(0), sys.argv.pop(0)
elif:
pass
print(cmd)
Strange way:
for x in (x for x in xrange(10) if someCondition):
print str(x)
You should use continue to skip a value, in both C and Python.
for i in range(10):
if someCondition:
continue
print(i)
You probably don't actually need the indices, you probably need the actual items. A better solution would probably be like this:
sequence = 'whatever'
for item in sequence:
if some_condition:
continue
do_stuff_with(item)
You could first turn the argv list into a generator:
def g(my_list):
for item in my_list:
yield item
You could then step through the items, invoking the generator as required:
my_gen = g(sys.argv[1:]):
while True:
try:
arg = my_gen.next()
if arg == "--flag1":
optX = my_gen.next()
opyY = my_gen.next()
--do something
elif arg == "--flag2":
optX = my_gen.next()
optY = my_gen.next()
optZ = my_gen.next()
--do something else
...
except StopIteration:
break
You can ensure that an index is incremented within a try...finally block. This solve the common problem of wanting to continue to the next index without having to copy/past i += 1 everywhere. Which is one of the main advantages the C-like for loop offers.
The main disadvantage to using a try...finally is having to indent your code once more. but if you have a while loop with many continue conditions its probably worth it.
Example
This example demonstrates that i still gets incremented in the finally block, even with continue being called. If i is not incremented its value will remain even forever, and the while loop will become infinite.
i = 0
while i < 10:
try:
print(i)
if i % 2 == 0:
continue
finally:
i += 1
without it you would have to increment i just before calling continue.
i = 0
while i < 10:
print(i)
if i % 2 == 0:
i += 1 # duplicate code
continue
i += 1
for i in xrange(0, 10):
if i % 3 == 0
continue
print i
Will only values which aren't divisible by 3.
If you need to iterate over something, and need an index, use enumerate()
for i, arg in enumerate(argv):
...
which does the same as the questioner's
for i in range(0,len(argv)):
arg = argv[i]
Your problem seems to be that you should loop not raw parameters but parsed parameters. I would suggest you to consider to change your decision not to use standard module (like the others).
increament = 4 #say
for i in range(n):
#write your code here
n=n+increment
this might be the simple solution to the problem if you just want to iterate through the array by skipping 4 members

Categories