python - 如何更改滑动窗口生成器一次跳转两个元素?

标签 python

我复制了显示的滑动窗口代码 here ,但我需要修改它以一次跳转两个元素而不是一个。
原始代码:

def window(seq, n=3):
    it= iter(seq)
    result = list(islice(it, n))
    if len(result) == n:
        yield result
    for elem in it:
        result = result[1:] + [elem,]
        yield result

如果我从以下列表开始:
My_List= ['adl_01_11', 'adl_01_12', 'adl_01_13', 'adl_01_14', 'adl_02_15', 'adl_02_16', 'adl_02_17', 'adl_02_18', 'adl_02_19', 'adl_02_20', 'adl_02_21', 'adl_02_22']
我将窗口应用于 My_List ,我得到以下结果:
[['adl_01_11', 'adl_01_12', 'adl_01_13'], ['adl_01_12', 'adl_01_13', 'adl_01_14'], ['adl_01_13', 'adl_01_14', 'adl_02_15'], ['adl_01_14', 'adl_02_15', 'adl_02_16'], ['adl_02_15', 'adl_02_16', 'adl_02_17'], ['adl_02_16', 'adl_02_17', 'adl_02_18'], ['adl_02_17', 'adl_02_18', 'adl_02_19'], ['adl_02_18', 'adl_02_19', 'adl_02_20'], ['adl_02_19', 'adl_02_20', 'adl_02_21'], ['adl_02_20', 'adl_02_21', 'adl_02_22']]
如果我想一次遍历 2 个项目,如何更改此函数?
这意味着我希望得到这样的结果:
[['adl_01_11', 'adl_01_12', 'adl_01_13'], ['adl_01_13', 'adl_01_14', 'adl_01_15'], ['adl_01_15', 'adl_01_16', 'adl_02_17'], ['adl_01_17', 'adl_02_18', 'adl_02_19'], ['adl_02_19', 'adl_02_20', 'adl_02_21']]
请注意 adl_02_22不再在结果中,我的窗口每 2 个项目迭代一次。
在窗口函数中,我尝试更改 result[1:]result[2:]但效果不佳。
任何的想法?

最佳答案

针对这个问题,我提出了三种解决方案:

  • 大小为 3 的窗口的特定窗口,步长为 2,
  • 具有任何窗口和步长的通用方法,
  • 跳过所有这些并使用现有的库。

  • 方案一:硬编码大小=3,步长=2的滑动窗口
    如果更换 for elem in it:等价的循环 while True:尝试的循环 next(it)直到 StopIteration被提出,这将让你使用 next(it)每次迭代两次而不是一次:
    def window_size3_step2(seq):
        it = iter(seq)
    
        try:
            result = [0,0,next(it)]
        except StopIteration:
            return
    
        while True:
            try:
                result = [result[2], next(it), next(it)]
            except StopIteration:
                break
            else:
                yield result
    
    
    My_List= ['adl_01_11', 'adl_01_12', 'adl_01_13', 'adl_01_14', 'adl_02_15', 'adl_02_16', 'adl_02_17', 'adl_02_18', 'adl_02_19', 'adl_02_20', 'adl_02_21', 'adl_02_22']
    
    print(f"{list(window_size3_step2(My_List))}")
    
    输出:
    [['adl_01_11', 'adl_01_12', 'adl_01_13'], ['adl_01_13', 'adl_01_14', 'adl_02_15'], ['adl_02_15', 'adl_02_16', 'adl_02_17'], ['adl_02_17', 'adl_02_18', 'adl_02_19'], ['adl_02_19', 'adl_02_20', 'adl_02_21']]
    
    测试较短的列表:
    for n in range(7):
        print(f"len={n} result={list(window_size3_step2(range(n)))}")
    
    len=0 result=[]
    len=1 result=[]
    len=2 result=[]
    len=3 result=[[0, 1, 2]]
    len=4 result=[[0, 1, 2]]
    len=5 result=[[0, 1, 2], [2, 3, 4]]
    len=6 result=[[0, 1, 2], [2, 3, 4]]
    
    方案二:任意大小和步长的通用窗函数
    第二个解决方案可以追溯到使用 islice考虑给定的窗口大小参数,我已将其重命名 size为了澄清,并接受 step也可以采用任何正整数值的参数。
    from itertools import islice
    def window(seq, size=3, step=1):
        if size < 1 or step < 1:
            raise ValueError("Nobody likes infinite loops.")
        it = iter(seq)
        result = list(islice(it, size))
        while len(result) == size:
            yield result
            if step >= size:
                result = list(islice(it, step-size, step))
            else:
                result = result[step:] + list(islice(it, step))
    
    在您的输入列表中,window(My_List, size=3, step=2) ,或只是 window(My_List, step=2) , 返回您想要的列表列表。
    我还用各种 seq 长度、大小和步长对此进行了测试,我可以确认它在所有情况下都能正常工作。例如,这个循环的输出(你自己试试,我不想把这么长的输出粘贴在这里)在每一行上都是正确的:
    for input_size in range(10):
        for window_size in range(1,4):
            for step_size in range(1,4):
                print(f"len={input_size} size={window_size} step={step_size} "
                      f"result={list(window(range(input_size), size=window_size, step=step_size))}")
    
    解决方案 3:有一个用于此的库!
    more_itertools库已经提供了一个函数来做到这一点:
    我必须先安装它:
    pip3 install more_itertools
    
    用它:
    from more_itertools import windowed
    print(f"{list(windowed(My_List, 3, step=2))}")
    
    [('adl_01_11', 'adl_01_12', 'adl_01_13'), ('adl_01_13', 'adl_01_14', 'adl_02_15'), ('adl_02_15', 'adl_02_16', 'adl_02_17'), ('adl_02_17', 'adl_02_18', 'adl_02_19'), ('adl_02_19', 'adl_02_20', 'adl_02_21'), ('adl_02_21', 'adl_02_22', None)]
    
    不过,这并不完全是您所要求的,因为它用 None 填充了最后一个不完整的窗口。 (或您提供的任何填充值)而不是截断结尾。
    虽然使用现有的库通常是一个不错的选择,但我在创建解决方案 1 和 2 方面学到了更多,我希望你能在这个过程中找到值(value)。
    学分:
    我在这里找到了 more_itertools 解决方案:https://stackoverflow.com/a/46412374/3216427

    关于python - 如何更改滑动窗口生成器一次跳转两个元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67318719/

    相关文章:

    c++ - 100选10,附加条件

    python - Pygame - 使用 Cx_Freeze 编译为 exe

    python - 如何正确引发 FileNotFoundError?

    python - 如何在 scikit-learn 中正确计算交叉验证分数?

    python - pip uninstall broken with -py2.7 in egg path

    python - Julia 中一维随机游走的直方图

    python - 我的方法不会调整图像的宽度和高度,它只是调整大小

    python - 查找字符串匹配模式

    python - 通过导入fastai.conv_learner产生SyntaxError

    python - 我想从列表创建一个数组,但保留 NaN 和 infs