简体   繁体   English

Python 向下枚举或使用自定义步骤

[英]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)?如何让Python的enumerate function从大到小枚举(降序、递减、倒数)? Or in general, how to use different step increment/decrement in enumerate ?或者一般来说,如何在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')] .例如,这样的 function,应用于列表['a', 'b', 'c'] ,起始值10 ,步长为-2 ,将产生迭代器[(10, 'a'), (8, 'b'), (6, 'c')]

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?如果你不理解上面的代码,请阅读Python 中的“yield”关键字做什么? and Difference between Python's Generators and Iterators . Python 的生成器和迭代器之间的区别

One option is to zip your iterable to a range :一种选择是将您的 iterable zip到一个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 ).这确实有一个限制,即您需要知道range应该走多远(它应该覆盖的最小值 - 在我的示例中,多余的部分将被zip截断)。

If you don't know, you could roll your own "infinite range " and use that:如果你不知道,你可以滚动你自己的“无限range ”并使用它:

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

Another option is to use itertools.count , which is helpful for "enumerating" by a step , in reverse .另一种选择是使用itertools.count ,它有助于反向“枚举” step

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()步进和方向逻辑紧凑地存储在count()
  • enumerated indices are iterated with next()枚举索引用next()迭代
  • count() is inherently infinite; count()本质上是无限的; useful if the terminal boundary is unknown (see @jonrsharpe)如果终端边界未知,则很有用(请参阅@jonrsharpe)
  • the sequence length intrinsically terminates the infinite iterator序列长度本质上终止了无限迭代器

Here is an idiomatic way to do that:这是一种惯用的方法:

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

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

May be not very elegant, using f'strings the following quick solution can be handy可能不是很优雅,使用 f'strings 下面的快速解决方案会很方便

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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