Reputation: 119
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
I need to write a windows generator takes an iterable and two ints (call them n and m; with m’s default value 1) as parameters: it produces lists of n values: the first list contains the first n values; every subsequent list drops the first m from the previous list and adds the next m values from the iterable, until there are fewer than n values to put in the returned list.
for instance:
for i in windows('abcdefghijk', 4,2):
print(i,end='')
prints ['a','b','c','d'] ['c','d','e','f'] ['e','f','g','h'] ['g','h','i','j']
.
when I call the above function, my code prints
[['i', 'j', 'k'], ['i', 'j', 'k'], ['i', 'j', 'k'], ['i', 'j', 'k']]
I cannot figure out the problem. can someone help me to fix it? Thanks in advance.
Upvotes: 4
Views: 1373
Reputation: 8521
The following will also work, and will not miss the end terms in some cases:
def sliding_window(iterable, window_size, step_size=1):
length = len(iterable)
i = 0
end_flag = False
while not end_flag:
curr_split = list(iterable[i:i + window_size])
if len(curr_split) < window_size:
end_flag = True
curr_split.extend([None] * (window_size - len(curr_split)))
yield curr_split
i += step_size
iterable = 'abcdefghijk'
window_size = 4
step_size = 2
res = list(sliding_window(iterable, window_size, step_size))
print(res)
Output:
[['a', 'b', 'c', 'd'],
['c', 'd', 'e', 'f'],
['e', 'f', 'g', 'h'],
['g', 'h', 'i', 'j'],
['i', 'j', 'k', None]]
Upvotes: 0
Reputation: 3706
appears to work for the few cases I tried, the generator itself is a one liner
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']
Upvotes: 0
Reputation: 21609
Maybe something like this, assuming you aren't working with a lazy iterable.
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)
output
['a', 'b', 'c', 'd']
['c', 'd', 'e', 'f']
['e', 'f', 'g', 'h']
['g', 'h', 'i', 'j']
Upvotes: 2
Reputation: 5384
You should use slicing to grab n
items and have a start value that increases by 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']
Upvotes: 2