Alternative to standard C "for"

  • Thread starter adomas.paltanavicius
  • Start date
A

adomas.paltanavicius

Hi there,

I am quite new to Python, and have a straight & simple question.
In C, there is for (init; cond; advance). We all know that.
In Python there are two ways to loop over i=A..B (numerical.):
1) i = A
while i<B:
...do something...
i+=STEP
2) for i in range(A, B, STEP):
...do something...

First case looks quite nasty, because it's for more complicated
things, not numerical loops. Second is very nice, but with there's
problem. If i do ..in range(1, 100000000).. (what I really need
sometimes), it takes few hundred megs of memory and slows
down. Are there other good ways for this simple problem? Generators?

Adomas
 
P

Paul Rubin

problem. If i do ..in range(1, 100000000).. (what I really need
sometimes), it takes few hundred megs of memory and slows
down. Are there other good ways for this simple problem? Generators?

use xrange instead of range.
 
?

=?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=

I am quite new to Python, and have a straight & simple question.
In C, there is for (init; cond; advance). We all know that.
In Python there are two ways to loop over i=A..B (numerical.):
1) i = A
while i<B:
...do something...
i+=STEP

This is indeed quite ugly. You rarely need such loops in Python and
with some thinking you can often translate the C-equivalent to
something more pythonic. As you guessed, your second problem is best
solved with a generator function - xrange(). It is completely equal to
range() except that it returns a generator instead of a list.
 
D

Daniel Bickett

Are there other good ways for this simple problem? Generators?

Very interesting problem :) That never occured to me.

To prevent python from loading that entire list into memory, one
could, as you suggested, use a generator:
while start < stop:
yield start
start += step
print "%s " % str( x ),

0 1 2 3 4
print "%s " % str( x ),

0 1 2 3 4
 
G

Georg Brandl

BJörn Lindqvist said:
This is indeed quite ugly. You rarely need such loops in Python and
with some thinking you can often translate the C-equivalent to
something more pythonic. As you guessed, your second problem is best
solved with a generator function - xrange(). It is completely equal to
range() except that it returns a generator instead of a list.

Slight terminology glitch -- it does return an iterator, not a
generator. Generators are functions that return iterators.

regards,
Georg
 
D

Diez B. Roggisch

First case looks quite nasty, because it's for more complicated
things, not numerical loops. Second is very nice, but with there's
problem. If i do ..in range(1, 100000000).. (what I really need
sometimes), it takes few hundred megs of memory and slows
down. Are there other good ways for this simple problem? Generators?

Use xrange(). It computes the values as they are needed - not an entire
list.
 
A

Alex Martelli

Georg Brandl said:
Slight terminology glitch -- it does return an iterator, not a
generator. Generators are functions that return iterators.

xrange returns an ITERABLE, not an ITERATOR. Videat:
Traceback (most recent call last):

No next method -> not an iterator. iter(xrange(...)) DOES return an
iterator, btw.


Alex
 
G

Georg Brandl

Alex said:
xrange returns an ITERABLE, not an ITERATOR. Videat:

Traceback (most recent call last):


No next method -> not an iterator. iter(xrange(...)) DOES return an
iterator, btw.

*wince*

This was SO clear...

Georg
 
G

Georg Brandl

Alex said:
xrange returns an ITERABLE, not an ITERATOR. Videat:

Traceback (most recent call last):


No next method -> not an iterator. iter(xrange(...)) DOES return an
iterator, btw.

Thanks! Somehow it's always these little corrections that contain errors.

And, considering your other posts today, I got away quite well...

Georg
 
S

Steve Holden

Hi there,

I am quite new to Python, and have a straight & simple question.
In C, there is for (init; cond; advance). We all know that.
In Python there are two ways to loop over i=A..B (numerical.):
1) i = A
while i<B:
...do something...
i+=STEP
2) for i in range(A, B, STEP):
...do something...

First case looks quite nasty, because it's for more complicated
things, not numerical loops. Second is very nice, but with there's
problem. If i do ..in range(1, 100000000).. (what I really need
sometimes), it takes few hundred megs of memory and slows
down. Are there other good ways for this simple problem? Generators?

Adomas
This question is so important to you you had to post it twelve times? :)

Look at "xrange", which is similar to range but doesn't create the whole
list.

regards
Steve
 
J

Jeremy Bowers

It seems I need constructs like this all of the time

i = 0
while i < len(somelist):
if oughta_pop_it(somelist):
somelist.pop(i)
else:
i += 1

There has to be a better way...

Any thoughts?


Others have pointed out

somelist = [x for x in somelist if not oughta_pop_it(x)]

but I'd also point out what I haven't seen, that your algorithm is O(n^2)
making fairly reasonable assumptions, whereas the list comprehension is
O(n). For long lists, that adds up fast. In fact, if you pop two things
off in the first half of the list, you've already lost and everything
after that is a waste.

The only time you want to do that is when you're memory-constrained, since
it will take less memory... and I gotta say, I don't think Python is the
best "memory-constrained" language in the world :) Besides, if you're
really dealing with that much data, it's probably time to use a database
of some sort and tell *it* what things to eliminate.
 
J

James Stroud

This is indeed quite ugly. You rarely need such loops in Python and
with some thinking you can often translate the C-equivalent to
something more pythonic. As you guessed, your second problem is best
solved with a generator function - xrange(). It is completely equal to
range() except that it returns a generator instead of a list.

It seems I need constructs like this all of the time

i = 0
while i < len(somelist):
if oughta_pop_it(somelist):
somelist.pop(i)
else:
i += 1

There has to be a better way...

Any thoughts?

James
 
M

Michael Spencer

James said:
It seems I need constructs like this all of the time

i = 0
while i < len(somelist):
if oughta_pop_it(somelist):
somelist.pop(i)
else:
i += 1

There has to be a better way...

Do you have to modify your list in place?

If not, just create a copy with the filtered items:

somelist = [item for item in somelist if not oughta_pop_it(item)]

or you could use filter or itertools.ifilter to do much the same thing

Michael
 
K

Kent Johnson

James said:
It seems I need constructs like this all of the time

i = 0
while i < len(somelist):
if oughta_pop_it(somelist):
somelist.pop(i)
else:
i += 1

There has to be a better way...


somelist[:] = [ item for item in somelist if not oughta_pop_it(item) ]

Kent
 
J

John Machin

James said:
It seems I need constructs like this all of the time

i = 0
while i < len(somelist):
if oughta_pop_it(somelist):
somelist.pop(i)
else:
i += 1

There has to be a better way...


! for i in xrange(len(somelist)-1, -1, -1):
! if oughta_pop_it(somelist):
! del somelist # why use pop??

We don't need no stinking iterators; we're the
Python_1.5_or_earlier_istas!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,219
Messages
2,571,120
Members
47,741
Latest member
WilliamsFo

Latest Threads

Top