除了Python中迭代器的最后N个元素之外的所有元素

时间:2011-07-09 02:29:42

标签: python iterator

在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]

6 个答案:

答案 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 usec0.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)