如何枚举从1开始的一系列数字

218

我正在使用Python 2.5,想要一个像下面这样的枚举(从1开始而不是0):

[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

我知道在Python 2.6中,你可以这样做:h = enumerate(range(2000, 2005), 1),来得到上述结果,但是在Python 2.5中你不能这样做…

使用Python 2.5:

>>> h = enumerate(range(2000, 2005))
>>> [x for x in h]
[(0, 2000), (1, 2001), (2, 2002), (3, 2003), (4, 2004)]

有人知道在Python 2.5中如何获得所需的结果吗?


5
只是好奇,因为我是一个在职业上没有做过太多Python的人。你是否被限制在Python 2.5上,因为你的公司不想为了兼容性原因进行升级? - Sean
2
所有的2.x版本都向后兼容,所以这不是问题。 - Jochen Ritzel
告诉一些模块 - 有一些工作在 Py 2.5 中但不工作在 Py 2.6中。 - xorsyst
12个回答

245

如你所提到的,这在 Python 2.6 或更新版本中是很容易实现的:

enumerate(range(2000, 2005), 1)

Python 2.5 及更早版本不支持 start 参数,因此您可以创建两个 range 对象并将它们压缩在一起:

r = xrange(2000, 2005)
r2 = xrange(1, len(r) + 1)
h = zip(r2, r)
print h

结果:

[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

如果你想创建一个生成器而不是列表,那么可以使用 izip


使用 izipxrange 更接近于 enumerate - John La Rooy
12
这个回答已经过时了。从Python 2.6开始,你现在只需要使用enumerate(iterable, start=1)即可。 - Fredrick Brennan
@frb:你看了问题吗?他已经知道Python 2.6的解决方案了。他特别要求一个在Python 2.5中可行的解决方案。 - Mark Byers
1
@MarkByers 看来我瞎了 :) 对此深感抱歉。(在谷歌搜索"从1开始枚举"中排名第一) - Fredrick Brennan
2
@8chan,没错,我刚从谷歌搜索“Python中enumerate从零开始吗”来到这里 :) - baxx

197

为了记录,需要提及一下,在2.6版本中,"start"参数被添加到枚举函数中:

enumerate(sequence, start=1)

该函数用于在遍历可迭代序列时返回一个带有索引的元组序列。通过指定起始值,可以控制索引的起始位置。

38
请注意,这并不会跳过列表中的第一项,而是通过起始值对索引进行偏移,因此如果您在代码中执行 sequence[i] 这样的操作,就会得到一个数组越界的错误。 - phyatt

42

Python 3

Python 官方文档: enumerate(iterable, start=0)

无需像其他回答中建议的编写自己的生成器,Python 标准库中已经包含了一个功能完全符合你要求的函数:

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
内置函数与此相当:
def enumerate(sequence, start=0):
  n = start
  for elem in sequence:
    yield n, elem
    n += 1

14

很简单,只需定义自己的函数以执行所需操作:

def enum(seq, start=0):
    for i, x in enumerate(seq):
        yield i+start, x

10

在Python 2.5中实现与您提出的要求完全相同的最简单方法:

import itertools as it

... it.izip(it.count(1), xrange(2000, 2005)) ...
如果你需要一个列表,建议使用 zip 替代 it.izip
(顺便说一句,通常情况下,将生成器或任何可迭代对象 X 转为列表的最佳方法不是使用 [x for x in X],而是使用 list(X)。)

6
from itertools import count, izip

def enumerate(L, n=0):
    return izip( count(n), L)

# if 2.5 has no count
def count(n=0):
    while True:
        yield n
        n+=1

现在h = list(enumerate(xrange(2000, 2005), 1))可以使用。

6

枚举是简单的,而重新实现它以接受起始值也同样简单:

def enumerate(iterable, start = 0):
    n = start
    for i in iterable:
        yield n, i
        n += 1

请注意,这不会影响使用enumerate而没有开始参数的代码。另外,以下的一行代码可能更加优雅且可能更快,但会破坏其他使用enumerate的方式:
enumerate = ((index+1, item) for index, item)

后者是纯粹的无意义话语。@Duncan的包装方式是正确的。

是的,完全胡说八道。在Haskell中,类似这样的东西实际上可以工作(柯里化在该语言中是最自然的事情,由于其惰性,接受列表的函数非常类似于生成器表达式)。但这并不能为我 - 长期使用Python的用户 - 写下胡言乱语提供借口。感谢您指出这一点。 - user395760

5
>>> list(enumerate(range(1999, 2005)))[1:]
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

枚举应该是一个生成器。一次性创建整个列表,然后迭代通常是不可接受的。 - John La Rooy
通用的:start=4 list(enumerate(range(start)+range(1999, 2005)))[start:] - Tony Veijalainen
range在2.52中是一个列表。 - Tony Veijalainen

3

h = [(i + 1, x) for i, x in enumerate(range(2000, 2005))]

注:此代码是在Python中创建一个名为"h"的列表,其中包含元组,每个元组都由索引值和从2000到2004的整数之一组成。

1
他无法在Python 2.5中执行此操作。start参数是在Python 2.6中引入的:http://docs.python.org/library/functions.html#enumerate。他在问题中也提到了这一点。 - Mark Byers
在最初的编辑时,我已经回答过这个问题了。当时代码格式不正确,而且问题似乎是使用了生成器而不是列表。 - Chris B.
++:这就是正确的做法。 - Nas Banov

2

好的,我感觉有点傻...为什么不直接使用类似于
[(a+1,b) for (a,b) in enumerate(r)] 的方法呢?如果不适用函数也没关系:

>>> r = range(2000, 2005)
>>> [(a+1,b) for (a,b) in enumerate(r)]
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

>>> enumerate1 = lambda r:((a+1,b) for (a,b) in enumerate(r)) 

>>> list(enumerate1(range(2000,2005)))   # note - generator just like original enumerate()
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接