在Python中获取迭代器的最后N个元素的最佳方法是什么?以下是理论行动中的一个例子:
>>> list(all_but_the_last_n(range(10), 0))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(all_but_the_last_n(range(10), 2))
[0, 1, 2, 3, 4, 5, 6, 7]
答案 0 :(得分:6)
只是为了它的乐趣,这里是Ignacio解决方案的变体,不需要deque。
>>> def truncate(it, n):
... cache = [next(it) for i in range(n)]
... index = 0
... for val in it:
... val, cache[index] = cache[index], val
... index = (index + 1) % n
... yield val
当我写上面的内容时,我并不特别关心速度......但也许这会更快一点:
def truncate(it, n):
cache = [next(it) for i in range(n)]
index = 0
for val in it:
yield cache[index]
cache[index] = val
index = (index + 1) % n
答案 1 :(得分:5)
使用collections.deque
。在第一次调用时从源中推送N
项。在每次后续调用中,弹出一个项目,从源中推送一个项目,然后生成弹出的项目。
答案 2 :(得分:3)
基于Ignacio Vazquez-Abrams的描述:
from collections import deque
def all_but_the_last_n(iterable, count):
q = deque()
i = iter(iterable)
for n in range(count):
q.append(i.next())
for item in i:
q.append(item)
yield q.popleft()
我想知道从右到左(附加,popleft)或从左到右(appendleft,pop)使用deque是否更好。所以我用python 2.5.2计时,发现rtl是3.59 usec
,而ltr是3.53 usec
。 0.06 usec
的差异并不显着。测试是附加一个项目并弹出一个项目。
答案 3 :(得分:1)
使用Ignacio的解决方案。
import collections
def all_but_the_last_n(iterable, n):
it = iter(iterable)
fifo = collections.deque()
for _, i in zip(range(n), it):
fifo.append(i)
for i in it:
fifo.append(i)
yield fifo.popleft()
print(list(all_but_the_last_n(range(10), 3)))
print(list(all_but_the_last_n('abcdefghijkl', 3)))
遗憾的是collections
没有循环缓冲区。从缓存未命中的角度来看,这将更有效。
答案 4 :(得分:1)
对于列表,您可以这样做:
def all_but_the_last_n(aList, N):
return aList[:len(aList) - N]
myList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
N = 4
print(all_but_the_last_n(myList, N))
将打印:
[0, 1, 2, 3, 4, 5]
答案 5 :(得分:0)
这很紧凑(除了consume
食谱中的itertools
食谱之外),并且应该以C速度运行:
import collections
import operator
from itertools import islice, tee
def truncate(iterable, n):
a, b = tee(iterable)
consume(b, n)
return map(operator.itemgetter(0), zip(a, b))
# From itertools recipes
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)