使用生成器时访问连续项


问题内容

可以说我有一个元组生成器,其模拟如下:

g = (x for x in (1,2,3,97,98,99))

对于这个特定的生成器,我希望编写一个函数来输出以下内容:

(1,2,3)
(2,3,97)
(3,97,98)
(97,98,99)
(98,99)
(99)

因此,我要遍历三个连续的项目并打印它们,除非我快要结束了。

我函数的第一行应该是:

t = tuple(g)

换句话说,最好直接在元组上工作,还是与生成器一起工作可能会有所好处。如果可以使用两种方法都可以解决此问题,请说明两种方法的优缺点。另外,如果使用生成器方法可能是明智的选择,那么这种解决方案会如何?

这是我目前正在做的事情:

def f(data, l):
    t = tuple(data)
    for j in range(len(t)):
        print(t[j:j+l])

data = (x for x in (1,2,3,4,5))
f(data,3)

更新

请注意,我已经更新了函数,以使用第二个参数来指定窗口的长度。


问题答案:

如果一次可能需要三个以上的元素,并且不想将整个生成器加载到内存中,建议使用标准库中的dequefromcollections模块存储当前项集。一个deque(发音为“
deck”,意思是“双端队列”)可以从两端有效地推送和弹出值。

from collections import deque
from itertools import islice

def get_tuples(gen, n):
    q = deque(islice(gen, n))   # pre-load the queue with `n` values
    while q:                    # run until the queue is empty
        yield tuple(q)          # yield a tuple copied from the current queue
        q.popleft()             # remove the oldest value from the queue
        try:
            q.append(next(gen)) # try to add a new value from the generator
        except StopIteration:
            pass                # but we don't care if there are none left