有没有一种语法更简洁的方式编写以下内容?
gen = (i for i in xrange(10))
index = 5
for i, v in enumerate(gen):
if i is index:
return v
生成器应该具有一个gen[index]
表达式,该表达式充当列表,但在功能上与上述代码相同,这似乎是很自然的。
有没有一种语法更简洁的方式编写以下内容?
gen = (i for i in xrange(10))
index = 5
for i, v in enumerate(gen):
if i is index:
return v
生成器应该具有一个gen[index]
表达式,该表达式充当列表,但在功能上与上述代码相同,这似乎是很自然的。
index
对象实现甚至是一种好习惯__eq__
?(这是下车的话题...)
Answers:
一种方法是使用 itertools.islice
>>> gen = (x for x in range(10))
>>> index = 5
>>> next(itertools.islice(gen, index, None))
5
您可以使用count
示例生成器来做到这一点:
from itertools import islice, count
next(islice(count(), n, n+1))
AttributeError: 'itertools.islice' object has no attribute 'next'
3.3中的错误。
next
为__next__()
,即islice(count, n, n=1).__next__()
next(islice(count(), n, n+1))
。
next(islice(count(), n, None))
。
我认为最好的方法是:
next(x for i,x in enumerate(it) if i==n)
(it
您的迭代器在哪里n
,索引在哪里)
它不需要您添加导入(例如使用的解决方案itertools
),也不需要一次将迭代器的所有元素加载到内存中(例如使用的解决方案list
)。
注意1:StopIteration
如果您的迭代器的项目少于n个,则此版本将引发错误。如果您想None
取而代之,可以使用:
next((x for i,x in enumerate(it) if i==n), None)
注意2:对的调用中没有方括号next
。这不是列表理解,而是生成器理解,它不消耗原始迭代器的第n个元素。
我反对将生成器视为列表的诱惑。简单但幼稚的方法是简单的一线:
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
一旦开始通过生成器获取序列中的第n个值,生成器现在处于不同的状态,再次尝试获取第n个值将返回不同的结果,这很可能会导致您的错误码。
让我们看看另一个示例,它基于问题中的代码。
最初,人们会期望以下内容打印4
两次。
gen = (i for i in range(10))
index = 4
for i, v in enumerate(gen):
if i == index:
answer = v
break
print(answer)
for i, v in enumerate(gen):
if i == index:
answer = v
break
print(answer)
但是将其输入到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)
永远不会结束。
您可以通过一种方法将延迟评估的缓存包装器放在无限生成器周围,使它看起来像可以随意索引的无限长列表,但这值得它自己的问题和答案,并且会对性能产生重大影响。
最好使用的是: 示例:
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)
->这将计算您拥有的对象数
希望我让它更简单。
也许您应该详细说明实际的用例。
>>> gen = xrange(10)
>>> ind=5
>>> gen[ind]
5
xrange(10)
为(i for i in xrange(10))
。事实证明,此语法适用,xrange
因为它并不是真正的生成器……
xrange
在生成器之前,并返回一个xrange对象,该对象实际上实现了完整序列协议。
is
在这种情况下(或根本没有很多情况)。is
是用于比较身份,而不是平等。你要==
。在这种情况下,这可能会起作用,但只能通过巧合和实现细节来实现。