zoukankan      html  css  js  c++  java
  • Python之滑动窗口

    需求

    对于一个数组array = ["n","v","l","f",...,"y","c","k"];

    • input
      • 当前位置 index
      • 数组的长度 arraySize
      • 基于当前位置,(前/后)滑动窗口的元素数目 windowSize
        • 即 滑动窗口(假定:包含当前元素 array[idx]) 总长:2*windowSize+1
    • output
      • 滑动窗口中的元素下标数组
        • 形如
          • 【中间】idx=3,arraySize=7,windowSzie=2 => [1,2,3,4,5]
          • 【偏前】idx=0,arraySize=7,windowSzie=2 => [5,6,0,1,2]
          • 【偏后】idx=6,arraySize=7,windowSzie=2 => [4,5,6,1,0]

    实现思路

    • [1] 循环队列
    • [2] 充分利用模运算的特点:最左边下标 (idx-windowSize)%arraySize 与 最后边下标(idx+windowSize)%arraySize可计算出来

    源码 一

    利用思路2,节省更多计算资源。
    目前存在一种bug,比如 (2,10,3)

    class CollectionUtil:
        def window(idx,arraySize,windowSize,containsCenterIdx=True): # 实现滑动窗口
            """
            获得当前位置的滑动窗口[元素的下标数组]
            -----------------------------------
            + idx : 当前位置下标
            + containsCenterIdx : 返回结果中,是否需要包含idex索引本身
            + 获得长为arraySize的列表中,以idex为中心,前后分别长windowSize个元素的的滑动窗口的元素下标数组
            + 默认数组下标最小为0
            + 滑动窗口总长 2*windowSize+1
            + 博文 [url] https://www.cnblogs.com/johnnyzen/p/10905958.html
            """
            if idx>=arraySize or idx < 0 or arraySize<1:
                raise ValueError("idx '",idx,"' out of arraySize '",arraySize,"' or them is error value!");
            if 2*windowSize+1 > arraySize:
                raise ValueError("2*windowSize+1 > arraySize! [ windowSize:",windowSize," | arraySize:",arraySize," ]");
            window = [];
            leftStart = (idx-windowSize)%(arraySize-1);  # 1,10,3 -> 7,8,9,0,1,2,3
            rightEnd = (idx+windowSize)%(arraySize-1);  # 9  0  1  2
            isRightWindowContinuous = True if idx+windowSize==rightEnd else False; # 判断右半窗口是否连贯
            for i in range(leftStart,leftStart + windowSize): # range(m,n) = [m,n)
                window.append(i);
                pass;
            if containsCenterIdx == True:
                window.append(idx);
            if isRightWindowContinuous == True:
                for i in range(rightEnd-windowSize+1,rightEnd+1): # 2-4+1
                    window.append(i);
                    pass;
            else : # 不连贯 即 右半窗口,一部分在数组开头,一部分在数组结尾
                for i in range(idx+1,arraySize-1+1):
                    window.append(i);
                    pass;
                for i in range(0,rightEnd):
                    window.append(i);
                    pass;
            return window;
    
    

    测试

    print(CollectionUtil.window(1,10,3)); # [7, 8, 9, 1, 2, 3, 4]
    print(CollectionUtil.window(9,10,3)); # [6, 7, 8, 9, 0, 1, 2]
    print(CollectionUtil.window(8,10,4)); # [4, 5, 6, 7, 8, 9, 0, 1, 2]
    print(CollectionUtil.window(7,10,4)); # [3, 4, 5, 6, 7, 8, 9, 0, 1]
     # print(CollectionUtil.window(3,7,2)); # [1,2,3,4,5]
     # print(CollectionUtil.window(0,7,2)); # [5,6,0,1,2]
     # print(CollectionUtil.window(6,7,2)); # [4,5,6,0,1]
    

    源码 二

    利用循环队列,目前没有bug。

    class CircularQueue: # 循环队列
        def __init__(self):
            self.queue = []*0; # 空列表
            self.cursor = 0;
        
        def push(self,eles):
            if isinstance(eles,Iterable) == True: # 可遍历类型  字符串("dsvvdsv")、列表、元组、字典、集合等
                for ele in eles:
                    self.queue.append(ele);
                pass;
            else : # 其他,默认为 单元素处理
                self.queue.append(eles);
        
        def pop(self,index=-1):
            return self.queue.pop(index); # index=-1 : 移除最后一个元素
            pass;
        
        def index(self,obj):
            return self.queue.index(obj);
    
        def length(self):
            return len(self.queue);
    
        def next(self,idx=0):
            if idx >= len(self.queue)-1:
                return {"index":0,"value":self.queue[0]};
            else :
                return {"index":(idx+1),"value":self.queue[idx+1]};
    
        def prev(self,idx=0):
            if idx <=0:
                return {"index":(len(self.queue)-1),"value":self.queue[len(self.queue)-1]};
            else :
                return {"index":(idx-1),"value":self.queue[idx-1]};
        
        def print(self):
            print("queue:",self.queue);
        
        def window(self,idx,arraySize,windowSize): # 滑动窗口
            windowIndexs = [];
            for i in range(0,arraySize):
                self.push(i); # 初始化
                pass;
            nextNodeCursor = self.next(idx);  # 下一节点游标
            prevNodeCursor = self.prev(idx);  # 上一节点游标
            for i in range(0,windowSize): # 加载前窗口元素
                windowIndexs.append(prevNodeCursor["value"]);
                prevNodeCursor = self.prev(prevNodeCursor["index"]);
                # self.pop(nextNode["index"]);
                pass;
            windowIndexs.append(idx);
            for i in range(0,windowSize): # 加载后窗口元素
                windowIndexs.append(nextNodeCursor["value"]);
                nextNodeCursor = self.next(nextNodeCursor["index"]);
                # self.pop(prevNode["index"]);
                pass;
            windowIndexs.sort(); # 返回前 排序
            return windowIndexs;
    

    测试

    print("window:",CircularQueue().window(2,10,3)); # window: [0, 1, 2, 3, 4, 5, 9]
    
  • 相关阅读:
    基于Visual C++2013拆解世界五百强面试题--题9-找出所有的排列方式
    基于Visual C++2013拆解世界五百强面试题--题8-数组的排序和查找
    基于Visual C++2013拆解世界五百强面试题--题7-链表的各种操作
    宣布在 Azure 镜像库中正式推出 Windows Server 2012 R2 并降低 Windows Azure 的实例定价
    基于Visual C++2013拆解世界五百强面试题--题6-double类型逆序
    基于Visual C++2013拆解世界五百强面试题--题5-自己实现strstr
    Paging
    Swapping
    Partitioning
    Stationary point
  • 原文地址:https://www.cnblogs.com/johnnyzen/p/10905958.html
Copyright © 2011-2022 走看看