Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

question about for cycle

6 views
Skip to first unread message

fdu.x...@gmail.com

unread,
Sep 29, 2007, 6:04:06 AM9/29/07
to pytho...@python.org
Hi all,

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,

Ant

unread,
Sep 29, 2007, 6:39:43 AM9/29/07
to
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

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...

Peter Otten

unread,
Sep 29, 2007, 7:36:26 AM9/29/07
to
Ant wrote:

> 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

Duncan Booth

unread,
Sep 29, 2007, 7:39:23 AM9/29/07
to
Ant <ant...@gmail.com> wrote:

> 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

John Machin

unread,
Sep 29, 2007, 9:01:26 AM9/29/07
to
On Sep 29, 8:04 pm, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com>
wrote:
[snip]

> 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

tok...@gmail.com

unread,
Sep 29, 2007, 9:38:43 AM9/29/07
to
On 29 sep, 12:04, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com> wrote:

> 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

fdu.x...@gmail.com

unread,
Sep 29, 2007, 10:34:21 AM9/29/07
to pytho...@python.org
In this case, the tuple generator_ab must be generated first. Sometime
it maybe a waste to generate all possible combinations of i,j first.

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,

George Sakkis

unread,
Sep 29, 2007, 11:19:04 AM9/29/07
to
On Sep 29, 10:34 am, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com>
wrote:

> tokl...@gmail.com wrote:
>
> > On 29 sep, 12:04, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com> wrote:
> >
> >> 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
> >
> In this case, the tuple generator_ab must be generated first.

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

Zentrader

unread,
Sep 29, 2007, 3:38:09 PM9/29/07
to
On Sep 29, 8:19 am, George Sakkis <george.sak...@gmail.com> wrote:
> On Sep 29, 10:34 am, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com>
> wrote:
>
>
>
> > tokl...@gmail.com wrote:
>
> > > On 29 sep, 12:04, "fdu.xia...@gmail.com" <fdu.xia...@gmail.com> wrote:
>
> > >> 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
>
> > In this case, the tuple generator_ab must be generated first.
> 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

tok...@gmail.com

unread,
Sep 29, 2007, 5:17:36 PM9/29/07
to
On 29 sep, 21:38, Zentrader <zentrad...@gmail.com> wrote:

> 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.

fdu.x...@gmail.com

unread,
Sep 29, 2007, 11:32:01 PM9/29/07
to pytho...@python.org
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.

Duncan Booth

unread,
Oct 1, 2007, 3:46:32 AM10/1/07
to
"fdu.x...@gmail.com" <fdu.x...@gmail.com> wrote:

>>> 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.

0 new messages