如何在迭代器上高效地进行“n 向”迭代

iz_*_*iz_ 5 python iterator list python-itertools python-3.x

可能是重复的,但我找不到任何东西。

\n\n

我有一个很长的迭代器(10000 个项目),我需要一次迭代约 500 个项目。所以如果我的迭代器是range(10000),它看起来像这样:

\n\n
Iteration #1: 0, 1, 2, ... 497, 498, 499\nIteration #2: 1, 2, 3, ... 498, 499, 500\nIteration #3: 2, 3, 4, ... 499, 500, 501\nIteration #4: 3, 4, 5, ... 500, 501, 502\n...\nIteration #9500: 9499, 9500, 9501 ... 9996, 9997, 9998\nIteration #9501: 9500, 9501, 9502 ... 9997, 9998, 9999\n
Run Code Online (Sandbox Code Playgroud)\n\n

等等。有这样一个方法:

\n\n
def nwise_slice(lst, n):\n    for i in range(len(lst) - n + 1):\n        yield lst[i:i + n]\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,这不适用于惰性迭代器。我尝试使用迭代器创建一个解决方案,并根据itertools pairwiseconsume食谱(请参阅此处)进行改编来创建此解决方案:

\n\n
import itertools\n\ndef nwise_iter(lst, n):\n    iters = itertools.tee(lst, n)\n    for idx, itr in enumerate(iters):\n        next(itertools.islice(itr, idx, idx), None)\n\n    for group in zip(*iters):\n        yield group\n
Run Code Online (Sandbox Code Playgroud)\n\n

其作用相同(尽管产生 atuple而不是 a list,这对我来说并不重要)。我还相信它不会创建很多不必要的切片。该解决方案适用于不可切片的迭代器,例如文件(我计划使用它)。然而,该itertools解决方案速度慢了 2 倍:

\n\n
In [4]: %timeit list(nwise_slice(list(range(10000)), 500))\n46.9 ms \xc2\xb1 729 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n\nIn [5]: %timeit list(nwise_iter(list(range(10000)), 500))\n102 ms \xc2\xb1 3.95 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不想将所有测试数据加载到内存中才能利用该slice方法。有没有更有效的方法来实现这一目标?

\n

Wal*_*oss 4

使用双端队列来“记忆”你的项目怎么样?

from collections import deque

def nwise_slice(it, n):
    deq = deque((), n)
    for x in it:
        deq.append(x)
        if len(deq)==n: yield deq

my_range = range(8)
for sub in nwise_slice(my_range, 5):
    print(sub)
# =>
# deque([0, 1, 2, 3, 4], maxlen=5)
# deque([1, 2, 3, 4, 5], maxlen=5)
# deque([2, 3, 4, 5, 6], maxlen=5)
# deque([3, 4, 5, 6, 7], maxlen=5)
Run Code Online (Sandbox Code Playgroud)