简体   繁体   中英

python for loop increasing or decreasing

I have to loop between two values where sometimes the first value is lesser that the second and some other times the first is greater than the second (I'm working on two cells inside a grid and the first cell can be on the left of the second or viceversa).

With python I can specify if a for loop has to decrease or to increase its values, but the result is something like that:

step = 1
if y<x:
    step = -1
for n in range(x,y,step):
    pass

Is there something more pythonic to obtain this? I'm using python 2.7 but moving to python 3 it wouldn't be a great issue .

Note that using step=-1 is not the same as a range from the smaller to the larger value!

>>> range(3, 7, 1)
[3, 4, 5, 6]
>>> range(7, 3, -1)
[7, 6, 5, 4]

The first one is from 3 to 6, the latter one from 4 to 7.

If that's still what you want, another way would be to use or :

>>> x, y = 7, 3
>>> range(x, y, x < y or -1)
[7, 6, 5, 4]

If you want to include both the lower and upper index, you have to offset the to index:

>>> step = +1 if x < y else -1 # or use that 'or' expression
>>> range(x, y + step, step)
[7, 6, 5, 4, 3]

Otherwise, you could sort the values first, either using min and max or sorted :

>>> x, y = sorted((x, y))
>>> range(x, y)
[3, 4, 5, 6]

Or in one line: range(*sorted((x, y))) (although I don't think this is very readable)


I did some timing analysis, ordering 1000 random x, y pairs (same pairs for each method):

  • x, y = sorted((x, y)) -> ~305µs for 1000 pairs
  • x, y = min(x, y), max(x, y) -> ~235µs for 1000 pairs
  • x, y = (x, y) if x < y else (y, x) -> ~75µs for 1000 pairs

So the ternary operator is the fastest, but in most cases it probably should not matter much, compared to the rest of the code (creating the range etc.)

I guess you could do something like this:

for n in xrange(min(x,y), max(x,y)):

Your way is already pretty much pythonic ;)

Edit: Shorter way suggest by @wap26:

for n in xrange(*sorted((x,y))):

Doesn't do much different to your code, but you could use this to calculate the step

range(x,y,(y-x)/abs(x-y))

For example:

In [10]: x,y = 5,10

In [11]: range(x,y,(y-x)/abs(x-y))
Out[11]: [5, 6, 7, 8, 9]

In [12]: x,y = 10,5

In [13]: range(x,y,(y-x)/abs(x-y))
Out[13]: [10, 9, 8, 7, 6]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM