'Python enumerate downwards or with a custom step
How to make Python's enumerate
function to enumerate from bigger numbers to lesser (descending order, decrement, count down)? Or in general, how to use different step increment/decrement in enumerate
?
For example, such function, applied to list ['a', 'b', 'c']
, with start value 10
and step -2
, would produce iterator [(10, 'a'), (8, 'b'), (6, 'c')]
.
Solution 1:[1]
I haven't found more elegant, idiomatic, and concise way, than to write a simple generator:
def enumerate2(xs, start=0, step=1):
for x in xs:
yield (start, x)
start += step
Examples:
>>> list(enumerate2([1,2,3], 5, -1))
[(5, 1), (4, 2), (3, 3)]
>>> list(enumerate2([1,2,3], 5, -2))
[(5, 1), (3, 2), (1, 3)]
If you don't understand the above code, read What does the "yield" keyword do in Python? and Difference between Python's Generators and Iterators.
Solution 2:[2]
One option is to zip
your iterable to a range
:
for index, item in zip(range(10, 0, -2), ['a', 'b', 'c']):
...
This does have the limitation that you need to know how far the range
should go (the minimum it should cover - as in my example, excess will be truncated by zip
).
If you don't know, you could roll your own "infinite range
" (or just use itertools.count
) and use that:
>>> def inf_range(start, step):
"""Generator function to provide a never-ending range."""
while True:
yield start
start += step
>>> list(zip(inf_range(10, -2), ['a', 'b', 'c']))
[(10, 'a'), (8, 'b'), (6, 'c')]
Solution 3:[3]
Here is an idiomatic way to do that:
list(zip(itertools.count(10,-2), 'abc'))
returns:
[(10, 'a'), (8, 'b'), (6, 'c')]
Solution 4:[4]
Another option is to use itertools.count
, which is helpful for "enumerating" by a step, in reverse.
import itertools
counter = itertools.count(10, -2)
[(next(counter), letter) for letter in ["a", "b", "c"]]
# [(10, 'a'), (8, 'b'), (6, 'c')]
Characteristics
- concise
- the step and direction logic is compactly stored in
count()
- enumerated indices are iterated with
next()
count()
is inherently infinite; useful if the terminal boundary is unknown (see @jonrsharpe)- the sequence length intrinsically terminates the infinite iterator
Solution 5:[5]
May be not very elegant, using f'strings the following quick solution can be handy
my_list = ['apple', 'banana', 'grapes', 'pear']
p=10
for counter, value in enumerate(my_list):
print(f" {counter+p}, {value}")
p+=9
> 10, apple
> 20, banana
> 30, grapes
> 40, pear
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |
Solution 2 | |
Solution 3 | David Rissato Cruz |
Solution 4 | |
Solution 5 | user172283 |