2017-02-09 52 views
3
def windows(iterable,n,m=1): 
    x = iter(iterable) 
    l = [] 
    y = next(x) 
    for i in range(n): 
     l.append(y) 
     y = next(x) 
    yield l 

    while x: 
     for i in range(m): 
      l.pop(0) 
     for i in range(m): 
      l.append(y) 
      y = next(x) 
     yield l 

滑動迭代的窗口長度爲n我需要編寫一個窗口發生器需要可迭代和兩個整數(稱它們爲n和m;其中m的默認值爲1)作爲參數:它產生的列表n個值:第一個列表包含前n個值;每個後續列表將刪除前一列表中的第一個m,並添加迭代中的下一個m值,直到返回列表中的值小於n個值。產生由步驟米

例如:

for i in windows('abcdefghijk', 4,2): 
    print(i,end='') 

打印['a','b','c','d'] ['c','d','e','f'] ['e','f','g','h'] ['g','h','i','j']

當我打電話上述功能,我的代碼打印

[['i', 'j', 'k'], ['i', 'j', 'k'], ['i', 'j', 'k'], ['i', 'j', 'k']] 

我想不通的問題。有人可以幫我解決它嗎?提前致謝。

+1

你每次都產生相同的列表對象;如果將它們全部保存並一次全部打印(而不是在生成時全部打印),那麼顯然它們都會打印相同的內容。嘗試''yield l [:]''在每個步驟中複製列表。 – jasonharper

+0

你可能也想'如果len(l)== n:yield l [:]'以避免返回'['i','j','k']'。 –

回答

1

您應該使用切片來抓取n項目並使其起始值增加m

def windows(iterable, n, m = 1): 
    if m == 0: # otherwise infinte loop 
     raise ValueError("Parameter 'm' can't be 0") 
    lst = list(iterable) 
    i = 0 
    while i + n < len(lst): 
     yield lst[i:i + n] 
     i += m 

# Output 
>>> for i in windows('abcdefghijk', 4, 2): 
    print(i) 

['a', 'b', 'c', 'd'] 
['c', 'd', 'e', 'f'] 
['e', 'f', 'g', 'h'] 
['g', 'h', 'i', 'j'] 
+0

有關無限循環的'm' == 0的好處。也許拋出一個'ValueError'可能是一個更好的方法來對付這個特殊的邊界情況? –

+0

@PaulRooney謝謝,'ValueError'似乎更合適。 –

1

也許這樣的事情,假設你沒有懶惰的迭代工作。

def windows(iterable, n, m=1): 
    length = len(iterable) 
    i = 0 

    while i + n < length: 
     yield list(iterable[i:i + n]) 
     i += m 

for win in windows('abcdefghijk', 4, 2): 
    print(win) 

輸出

​​
0

出現的少數情況下我想工作,發電機本身是一個內襯

def WindGen(astr, n, m = 1): 
    if m !=0: 
     return (list(astr[i * m : i * m + n]) for i in range((len(astr) - n) // m + 1))  

astr = 'abcdefghijk' 
n, m = 4, 2 
print(*WindGen(astr, n, m), sep='\n') 
['a', 'b', 'c', 'd'] 
['c', 'd', 'e', 'f'] 
['e', 'f', 'g', 'h'] 
['g', 'h', 'i', 'j']