从Python迭代器获取最后一项的最干净方法
在Python2.6中,从迭代器获取最后一项的最佳方法是什么?比如说从Python迭代器获取最后一项的最干净方法,python,python-3.x,python-2.7,iterator,Python,Python 3.x,Python 2.7,Iterator,在Python2.6中,从迭代器获取最后一项的最佳方法是什么?比如说 my_iter = iter(range(5)) 从my_iter获取4的最短代码/最干净的方法是什么 我可以这样做,但似乎效率不高: [x for x in my_iter][-1] 我会使用反向,但它只接受序列而不是迭代器,这似乎是任意的 无论如何,都必须运行整个迭代器。以最大效率,如果您不再需要迭代器,您可以丢弃所有值: for last in my_iter: pass # last is now the
my_iter = iter(range(5))
从my_iter
获取4
的最短代码/最干净的方法是什么
我可以这样做,但似乎效率不高:
[x for x in my_iter][-1]
我会使用
反向
,但它只接受序列而不是迭代器,这似乎是任意的
无论如何,都必须运行整个迭代器。以最大效率,如果您不再需要迭代器,您可以丢弃所有值:
for last in my_iter:
pass
# last is now the last item
不过,我认为这是一个次优的解决方案。有一个
list( the_iter )[-1]
如果迭代的长度真的是史诗般的——如此之长以至于具体化列表将耗尽内存——那么您真的需要重新考虑设计。由于lambda,这不太可能比空for循环快,但可能会给其他人一个主意
reduce(lambda x,y:y,my_iter)
如果iter为空,则会引发类型错误如果可用,则可能值得使用
if hasattr(my_iter,'__reversed__'):
last = next(reversed(my_iter))
else:
for last in my_iter:
pass
这个问题是错误的,只能导致一个复杂而低效的答案。 为了得到一个迭代器,您当然要从可iterable开始,在大多数情况下,这将提供一种更直接的方式来访问最后一个元素 一旦从iterable创建了迭代器,您就会陷入遍历元素的困境,因为这是iterable提供的唯一功能 因此,最有效和清晰的方法不是首先创建迭代器,而是使用iterable的本机访问方法 使用大小为1的
from collections import deque
#aa is an interator
aa = iter('apple')
dd = deque(aa, maxlen=1)
last_element = dd.pop()
有关类似的内容,请参见此代码: 您可以使用它拾取最后一个项目:
[(last, e) for (last, e) in islast(the_iter) if last]
简单到:
max(枚举(iter))[1]
如果您使用的是Python3.x,我将只使用下一步(反向(myiter))
:
*_, last = iterator # for a better understanding check PEP 448
print(last)
如果您使用的是python 2.7:
last = next(iterator)
for last in iterator:
continue
print last
旁注:
通常,上面介绍的解决方案是常规情况下所需的,但如果您处理大量数据,则使用大小为1的
deque
更有效。()
该库提供了一个很好的解决方案:
from toolz.itertoolz import last
last(values)
但添加非核心依赖项可能不值得仅在这种情况下使用。问题在于获取迭代器的最后一个元素,但如果迭代器是通过对序列应用条件创建的,则可以使用reversed来查找反转序列的“第一个”,只查看所需的元素,通过对序列本身应用反向 一个人为的例子
>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8
或者,对于无限迭代器,您可以使用:
from itertools import islice
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples
我以为它会比
deque
慢,但它和for-loop方法一样快,而且实际上比for-loop方法快(不知何故)迭代器假设您希望遍历元素,而不是真正访问最后的元素。是什么阻止了你简单地使用范围(5)[-1]?@Frank-我假设实际的迭代器比iter(范围(5))更复杂和/或更远和/或更难控制。@Frank:事实上,它是一个提供迭代器的更复杂的生成器函数。我只是编了一个简单明了的例子,如果你想要迭代器的最后一项,很有可能你做错了什么。但是答案是,实际上没有任何更干净的方法可以通过迭代器进行迭代。这是因为迭代器没有大小,实际上可能永远不会结束,因此可能没有最后一项。(当然,这意味着您的代码将永远运行)。所以一个挥之不去的问题是:你为什么想要迭代器的最后一项?@Peter:请更新你的问题。不要在自己的问题上添加一堆评论。请更新问题并删除注释。reversed()不接受迭代器,只接受序列。它完全不是任意的。反转迭代器的唯一方法是迭代到底,同时将所有项保留在内存中。一、 你需要先把它做一个序列,然后才能反转它。这当然首先违背了迭代器的目的,也意味着你会突然无缘无故地耗尽大量内存。事实上,这是武断的反面@伦纳特——当我说武断时,我的意思是讨厌。我把我的语言技能集中在早上这个时候几个小时后要交的论文上。这很公平。虽然依我看,如果它接受迭代器,会更烦人,因为几乎任何使用它的方法都是个坏主意(tm)为什么要使用占位符“defaultvalue”?为什么不None
?这正是None
的用途。您是否认为某些特定于函数的默认值可能是正确的?如果迭代器实际上没有进行迭代,那么带外值比某些误导性的特定于函数的默认值更有意义。如果要使用None
作为默认值,这是您的选择。无违约并不总是最明智的违约,甚至可能不会超出范围。就我个人而言,我倾向于使用'defaultvalue=object()'来确保它是一个真正唯一的值。我只是指出默认值的选择超出了本例的范围。@S.Lott:也许区分空迭代器和无迭代器的区别是有用的,因为它是最终值所有内置容器类型的迭代器中都存在设计错误?我第一次听说它:)虽然这可能是更快的解决方案,但它依赖于循环中的变量泄漏(对于某些人来说是一个特性,对于其他人来说是一个bug——可能FP的家伙们都感到震惊)。无论如何,Guido说这将始终以这种方式工作,因此使用它是安全的。这实际上是耗尽长序列的最快方式,尽管只比for循环快一点点
>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8
from itertools import islice
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples