获取Python中生成器的第n项
有没有一种更简洁的方式来写下面的内容获取Python中生成器的第n项,python,generator,Python,Generator,有没有一种更简洁的方式来写下面的内容 gen = (i for i in xrange(10)) index = 5 for i, v in enumerate(gen): if i is index: return v 生成器应该有一个用作列表的gen[index]表达式,但在功能上与上面的代码相同,这似乎很自然。也许您应该详细介绍一个实际的用例 >>> gen = xrange(10) >>> ind=5 >>>
gen = (i for i in xrange(10))
index = 5
for i, v in enumerate(gen):
if i is index:
return v
生成器应该有一个用作列表的
gen[index]
表达式,但在功能上与上面的代码相同,这似乎很自然。也许您应该详细介绍一个实际的用例
>>> gen = xrange(10)
>>> ind=5
>>> gen[ind]
5
一种方法是使用
您可以使用
count
作为示例生成器来执行此操作:
from itertools import islice, count
next(islice(count(), n, n+1))
我反对将生成器视为列表的诱惑。简单但幼稚的方法是简单的一行:
gen = (i for i in range(10))
list(gen)[3]
但请记住,生成器不像列表。他们不会把中间结果存储在任何地方,所以你不能倒退。我将用python repl中的一个简单示例演示此问题:
>>> gen = (i for i in range(10))
>>> list(gen)[3]
3
>>> list(gen)[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
但在repl中键入此项,您会得到:
>>> gen = (i for i in range(10))
>>> index = 4
>>> for i, v in enumerate(gen):
... if i == index:
... answer = v
... break
...
>>> print(answer)
4
>>> for i, v in enumerate(gen):
... if i == index:
... answer = v
... break
...
>>> print(answer)
9
祝你好运找到那只虫子
编辑:
如前所述,如果生成器无限长,您甚至无法将其转换为列表。表达式list(gen)
永远不会结束
有一种方法可以将一个经过延迟评估的缓存包装器放在一个无限生成器周围,使它看起来像一个无限长的列表,您可以随意将其编入索引,但这应该有自己的问题和答案,并且会对性能产生重大影响。我想到的第一件事是:
gen = (i for i in xrange(10))
index = 5
for i, v in zip(range(index), gen): pass
return v
最佳使用方法是: 例如:
a = gen values ('a','c','d','e')
因此,答案将是:
a = list(a) -> this will convert the generator to a list (it will store in memory)
然后,当您要转到特定索引时,您将:
a[INDEX] -> and you will able to get the value its holds
如果您只想知道计数或执行不需要存储在内存中的操作,最佳做法是:
a=sum(1 in i in a)
->这将计算您拥有的对象数
希望我能让它更简单 我认为最好的办法是:
next(x代表i,如果i==n,则枚举(it)中的x)
(其中,it
是迭代器,n
是索引)
它不要求您添加导入(如使用itertools
的解决方案),也不要求您同时在内存中加载迭代器的所有元素(如使用list
的解决方案)
注1:如果迭代器的项少于n项,此版本将抛出一个StopIteration
错误。如果您想获得None
,可以使用:
next((x代表i,如果i==n,则枚举(it)中的x),无)
注2:对
next
的调用中没有括号。这不是一个列表理解,而是一个生成器理解,它不会消耗原始迭代器超过其第n个元素。如果在编写时已知n
,则可以使用解构。e、 g.要获得第三项:
>>> [_, _, third, *rest] = range(10)
>>> third
2
>>> rest
[3, 4, 5, 6, 7, 8, 9]
我编辑了
xrange(10)
到(我代表xrange(10)中的I))
。事实证明,这种语法适用于xrange
,因为它不是真正的生成器…xrange
早于生成器,并返回一个xrange对象,该对象实际上实现了全序列协议。在这种情况下(或在许多情况下),您不希望是
<代码>是用于比较身份,而不是相等。您需要==
。这在这个例子中可能会起作用,但这只是巧合和实现细节。既然我使用的是整数,它怎么会不起作用呢?在这种情况下,期望索引
对象实现\uuuu eq\uuuu
是否是一种良好的做法?(这脱离了主题…)尝试1000是500+500
,它(可能)是False
。例如,这个问题见+1。说“gen的第n个结果”似乎有点奇怪。另一种可能是Zipper——它们处理任意树,但列表也是树。看到这个实现了吗?这是什么版本的Python?上面的代码给了我一个错误AttributeError:'itertools.islice'对象在3.3中没有属性'next'
。在Python 3x中,将next
改为\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,例如,next(islice(count(),n,None))
。如果生成器是无限的,该怎么办?这应该更高,因为这样做会在时间上付出巨大的代价。谢谢你指出这一点。我相信这将遍历整个迭代器,当迭代器需要很长时间才能完成时,速度会变慢。@ubershmekel:不会的!它将遍历前n个元素(当然),仅此而已。为什么不自己尝试一下呢?我在第二个注释中添加了一个注释,明确说明原始迭代器没有被完全使用
a[INDEX] -> and you will able to get the value its holds
>>> [_, _, third, *rest] = range(10)
>>> third
2
>>> rest
[3, 4, 5, 6, 7, 8, 9]