Source: Python Morsels

Description

Given an iterable nums and a “window” of width, return an iterator of tuples of the specified width.

1
2
3
>>> numbers = [1, 2, 3, 4, 5, 6]
>>> list(window(numbers, 2))
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]

Notes

None.

My solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def window(nums, width):
    '''Reformat the iterable `nums` as tuples of `width` each.
    
    Given an iterable `nums` and a "window" of `width`, return an 
    iterator of tuples of the specified width.

    >>> numbers = [1, 2, 3, 4, 5, 6]
    >>> list(window(numbers, 2))
    [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
    '''
    nums = list(nums)
    nlen = len(nums)
    for idx in range(nlen):
        try:
            if idx < nlen - (width - 1):
                yield tuple(nums[idx:idx + width])
        except IndexError:
            pass


# Tests

def test_window_len_even():
    numbers = [1, 2, 3, 4, 5, 6]
    result = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
    assert list(window(numbers, 2)) == result

def test_iterable_input():
    numbers = [1, 2, 3, 4, 5, 6]
    squares = (n ** 2 for n in numbers)
    result = [(1, 4, 9), (4, 9, 16), (9, 16, 25), (16, 25, 36)]
    assert list(window(squares, 3)) == result
        


# Interaction 

if __name__ == '__main__':
    print('My tests:')
    import doctest, pytest
    doctest.testmod()
    pytest.main([__file__])

    print('Provided tests:')
    from os import system
    system('python test_window.py')

Provided solution

Uses a deque, which is interesting but seems unnecessary for this particular problem.

1
2
3
4
5
6
7
8
9
10
from collections import deque
from itertools import islice

def window(iterable, n):
    iterator = iter(iterable)
    current = deque(islice(iterator, n), maxlen=n)
    yield tuple(current)
    for item in iterator:
        current.append(item)
        yield tuple(current)