python 改进itertools.pairwise()函数

vs91vp4v  于 2022-12-21  发布在  Python
关注(0)|答案(1)|浏览(200)

我试图创建一个自定义函数来改进itertools的pairwise函数。
不像pairwise函数,它返回的项目(n = 2),我希望能够指定分组长度(n = x),这样我就可以返回指定长度的项目组,这可能吗?
所以当n=2时,groupwise函数应该等价于itertools pairwise函数,但是当n=3时,我希望它返回3个一组的结果。
这就是我目前所知道的--它本质上与成对函数相同。即适用于n = 2

代码:

from itertools import tee

my_string = 'abcdef'

def groupwise(iterable, n):
    a = tee(iterable, n)
    next(a[n-1], None)
    return zip(a[0], a[1])

for item in groupwise(my_string, 2):
    print("".join(item))

输出:

ab
bc
cd
de
ef

我试图修改上面的代码以接受n=3, n=4, n=5, ... n=x,但是考虑到我想指定n <= len(my_string)的任何值,我想不出一种方法来为zip函数提供不确定数量的组件

    • 当n = 3时,输出应为:**
abc
bcd
cde
def
jjjwad0x

jjjwad0x1#

不幸的是,tee不会以这种方式扩展,编写pairwise需要一次tee调用,如果要对每个组中的N个元素执行此操作,则需要N-1次tee调用。
幸运的是,我们可以通过自己滚动循环来做得更好。我们要做的是跟踪我们自己看到的最后N个元素,每当我们有一个足够大的组时,就对它们执行yield。为此,我们需要一个数据结构,它可以有效地向右添加元素,并从左减去元素。collections.deque会做得很好。事实上,它甚至有一个maxlen参数,当我们需要它的时候,它会 * 自动 * 从左边减去。

from collections import deque

def groupwise(iterable, n):
    accum = deque((), n)
    for element in iterable:
        accum.append(element)
        if len(accum) == n:
            yield tuple(accum)

构造一个空的双端队列(第一个构造函数参数是初始元素:一个空元组),其容量为n。当我们在右侧添加超过n的元素时,它会自动删除最左侧的元素。我们可以手动完成此操作,但deque会为我们完成此操作,因此我们还不如利用它们提供的功能。
然后迭代可迭代对象,将每个元素附加到双端队列的末尾(根据需要从左开始,以满足最大长度要求),然后,如果双端队列有n个元素,我们就对它进行yield,这使得我们的函数成为generator function,因此它将产生一个新的迭代器,该迭代器包含所有yield ed值。
我们制作了一个deque的浅副本,这样我们就不会每次都产生相同的(可变的)deque对象,我们还制作了一个tuple的浅副本,而不是一个deque,以便与其他itertools功能更一致。
要调用,请使用

print(list(groupwise(range(10), 3)))
# Output: [(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7), (6, 7, 8), (7, 8, 9)]

相关问题