I have to loop between two values where sometimes the first value is less than 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 vice versa).
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?
How do you make a for loop decrease in Python? Use range() to iterate through a decreasing range with a for-loop. Call range(start, stop, step) with step as -1 to create a range from start down to but not including step . Use a for-loop to iterate through each integer in this range.
A for loop doesn't increment anything. Your code used in the for statement does. It's entirely up to you how/if/where/when you want to modify i or any other variable for that matter. That's not a for loop, it's an infinite loop.
But Python does have a built-in reversed function. If you wrap range() inside reversed() , then you can print the integers in reverse order. range() makes it possible to iterate over a decrementing sequence of numbers, whereas reversed() is generally used to loop over a sequence in reverse order.
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 pairsx, y = min(x, y), max(x, y)
-> ~235µs for 1000 pairsx, y = (x, y) if x < y else (y, x)
-> ~75µs for 1000 pairsSo 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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With