Python之滑動窗口

需求

對於一個數組array = ["n","v","l","f",...,"y","c","k"];html

  • 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)python

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。app

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;

測試ide

print("window:",CircularQueue().window(2,10,3)); # window: [0, 1, 2, 3, 4, 5, 9]
相關文章
相關標籤/搜索