Python enumerate downwards or with a custom step
Asked Answered
A

6

26

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')].

Ademption answered 18/6, 2014 at 15:54 Comment(0)
A
34

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.

Ademption answered 18/6, 2014 at 15:54 Comment(0)
A
10

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')]
Analyze answered 18/6, 2014 at 16:2 Comment(0)
S
3

Here is an idiomatic way to do that:

list(zip(itertools.count(10,-2), 'abc'))

returns: [(10, 'a'), (8, 'b'), (6, 'c')]

Statement answered 20/11, 2020 at 3:31 Comment(0)
E
2

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
Evanish answered 24/11, 2016 at 16:43 Comment(0)
I
0

If you don't need iterator keeped in variable and just iterate through some container, multiply your index by step.

container = ['a', 'b', 'c']
step = -2

for index, value in enumerate(container):
    print(f'{index * step}, {value}')


>>> 0, a
-2, b
-4, c
Immerge answered 2/1, 2023 at 17:13 Comment(0)
I
-1

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
Iorgo answered 16/9, 2020 at 10:40 Comment(1)
This seems to be a convoluted way of writing (counter + 1)*10.Loughlin

© 2022 - 2024 — McMap. All rights reserved.