I have the following code:
for i in generator_a: # the first "for" cycle
for j in generator_b:
if something_happen:
# do something here ..., I want the outer cycle to break
break
What should I do if I want the outer "for" cycle to continue or break ? If I
put a "continue" or "break" in the inner cycle, it has no effect on the outer
cycle.
And I have another question. Which is the most efficient way to check if there
are duplicate items in a list ? The items in the list may cannot be hashed, so
set() may not work on the list.
Regards,
I'd also be interested in the idiomatic solution to this one. I can
see a number of solutions, from the ugly:
for i in range(10):
do_break = True
for j in range(10):
if j == 6:
break
else:
do_break = False
if do_break:
break
This will break the outer loop if the inner loop exited with a break.
Using exceptions:
for i in range(10):
try:
for j in range(10):
print i, j
if j == 6:
raise MyException
except MyException, e:
break # or continue or whatever.
Encapsulating in a function and using return:
def get_value():
for i in range(10):
for j in range(10):
print i, j
if j == 6:
return fn(i, j)
I guess to an extent it would depend on the exact situation as to
which of these is more suitable. Are there any other recommended
solutions to this?
--
Ant...
> On Sep 29, 11:04 am, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com>
> wrote:
> ...
>> What should I do if I want the outer "for" cycle to continue or break ? If I
>> put a "continue" or "break" in the inner cycle, it has no effect on the outer
>> cycle.
>
> I'd also be interested in the idiomatic solution to this one. I can
> see a number of solutions, from the ugly:
>
> for i in range(10):
> do_break = True
> for j in range(10):
> if j == 6:
> break
> else:
> do_break = False
>
> if do_break:
> break
Here's a variant that doesn't need the flag
>>> inner = "abc"
>>> outer = "xbz"
>>> for i in outer:
... for k in inner:
... if i == k:
... print "found", i
... break
... else:
... print i, "not found"
... continue
... break
...
x not found
found b
but I usually prefer a helper function like this
> def get_value():
> for i in range(10):
> for j in range(10):
> print i, j
> if j == 6:
> return fn(i, j)
or this:
>>> def f(i, inner):
... for k in inner:
... if i == k:
... print "found", i
... return True
...
>>> for i in outer:
... if f(i, inner):
... break
... print i, "not found"
...
x not found
found b
Peter
> On Sep 29, 11:04 am, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com>
> wrote:
> ...
>> What should I do if I want the outer "for" cycle to continue or break
>> ? If I put a "continue" or "break" in the inner cycle, it has no
>> effect on the outer cycle.
>
...
> I guess to an extent it would depend on the exact situation as to
> which of these is more suitable. Are there any other recommended
> solutions to this?
>
I think the other Pythonic option you have missed is to convert the nested
for loops into a single loop by writing a generator.
def ranges(limit1, limit2):
range1, range2 = range(limit1), range(limit2)
for i in range1:
for j in range2:
yield i,j
...
for i, j in ranges(10, 10):
... whatever ...
if j==6:
break
> And I have another question. Which is the most efficient way to check if there
> are duplicate items in a list ? The items in the list may cannot be hashed, so
> set() may not work on the list.
The following classic by Tim Peters answers the question "How do I
remove duplicate items from a list".
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
It should help -- provided of course that you mean "duplicates" in the
sense that two Python objects a and b are duplicates iff a == b.
If you mean duplicates in a fuzzier sense e.g. "Mao Zedong" and "Mao
Tse-Tung", the problem gets harder ...
HTH,
John
> for i in generator_a: # the first "for" cycle
> for j in generator_b:
> if something_happen:
> # do something here ..., I want the outer cycle to break
> break
Do you like this?
generator_ab = ((x, y) for x in generator_a for y in generator_b)
for i, j in generator_ab:
if condition:
# do something
break
I have googled and found the PEP-3136(Labeled break and continue),
which has been rejected. I have also read why Guido rejected this PEP(
http://mail.python.org/pipermail/python-3000/2007-July/008663.html),
but I still think labeled break and continue is a good feature in my
case.
Regards,
It's not a tuple, it is a generator expression that can generate
tuples *lazily*.
> Sometime it maybe a waste to generate all possible combinations of i,j first.
It doesn't; read about generator expressions at http://www.python.org/dev/peps/pep-0289/
George
You can get specific break points by expanding the for loop into a
while loop, and this is perhaps why it has never been implemented with
for loops.
ctr_a=0
ctr_b=0
while ctr_a < len(generator_a):
this_el_a = generator_a[ctr_a]
while ctr_b < len(generator_b):
this_el_b = generator_b[ctr_ b]
if something_happen:
ctr_b = len(generator_b) ## break this loop
if something_else:
ctr_a = len(generator_a) ## break outer while loop
ctr_b += 1
ctr_a += 1
> ctr_a=0
> ctr_b=0
> while ctr_a < len(generator_a):
> this_el_a = generator_a[ctr_a]
> while ctr_b < len(generator_b):
> this_el_b = generator_b[ctr_ b]
> if something_happen:
> ctr_b = len(generator_b) ## break this loop
> if something_else:
> ctr_a = len(generator_a) ## break outer while loop
> ctr_b += 1
> ctr_a += 1
Mmm, isn't a bit complicated?
Anyway, neither len() nor __getitem__ work on generators.
However, I still think labeled break and continue is a valuable feature, which
is easier to understand and to use.
>>> Sometime it maybe a waste to generate all possible combinations of
>>> i,j first.
>>
>> It doesn't; read about generator expressions at
>> http://www.python.org/dev/peps/pep-0289/
>>
>> George
>>
> Thanks, I didn't realize that.
>
> However, I still think labeled break and continue is a valuable
> feature, which is easier to understand and to use.
>
Can you come up with a realistic example where you think a labelled break
would be easier to understand and use? A concrete example would really help
if you hope to persuade anyone that your way is better.
I find that Python's ability to extract the control part of a loop into a
generator is an extremely powerful way to make loops much clearer for
several reasons: you separate completely the 'what we are looping over',
and 'when do we stop' from the 'what do we then do with each item'; also
you have an opportunity to give the code controlling the loop a separate
(and meaningful) name.