Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over a ‘window’ of adjacent elements in Python

Tags:

python

This is more a question of elegance and performance rather than “how to do at all”, so I'll just show the code:

def iterate_adjacencies(gen, fill=0, size=2, do_fill_left=True,
  do_fill_right=False):
    """ Iterates over a 'window' of `size` adjacent elements in the supploed
    `gen` generator, using `fill` to fill edge if `do_fill_left` is True
    (default), and fill the right edge (i.e.  last element and `size-1` of
    `fill` elements as the last item) if `do_fill_right` is True.  """
    fill_size = size - 1
    prev = [fill] * fill_size
    i = 1
    for item in gen:  # iterate over the supplied `whatever`.
        if not do_fill_left and i < size:
            i += 1
        else:
            yield prev + [item]
        prev = prev[1:] + [item]
    if do_fill_right:
        for i in range(fill_size):
            yield prev + [fill]
            prev = prev[1:] + [fill]

and then ask: is there already a function for that? And, if not, can you do the same thing in a better (i.e. more neat and/or more fast) way?

Edit:

with ideas from answers of @agf, @FogleBird, @senderle, a resulting somewhat-neat-looking piece of code is:

def window(seq, size=2, fill=0, fill_left=True, fill_right=False):
    """ Returns a sliding window (of width n) over data from the iterable:
      s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...
    """
    ssize = size - 1
    it = chain(
      repeat(fill, ssize * fill_left),
      iter(seq),
      repeat(fill, ssize * fill_right))
    result = tuple(islice(it, size))
    if len(result) == size:  # `<=` if okay to return seq if len(seq) < size
        yield result
    for elem in it:
        result = result[1:] + (elem,)
        yield result
like image 644
HoverHell Avatar asked Aug 09 '11 14:08

HoverHell


People also ask

How do you iterate over an object in Python?

You can create an iterator object by implementing the iter built-in function to an iterable. An iterator can be used to manually loop over the items in the iterable. The repeated passing of the iterator to the built-in next function returns successive items in the stream.

Can you iterate through two lists simultaneously Python?

Iterate over multiple lists at a time We can iterate over lists simultaneously in ways: zip() : In Python 3, zip returns an iterator. zip() function stops when anyone of the list of all the lists gets exhausted. In simple words, it runs till the smallest of all the lists.

How do you iterate through elements?

To iterate over the selected elements, you can use forEach() method (supported by most modern web browsers, not IE) or just use the plain old for-loop.

How do you loop through a pair in Python?

Solution: To iterate over a Python list lst in pairs, iterate over all list indices i from 0 to the index of the second last list element (included). In the loop body, use the indices to retrieve the windows by slicing lst[i:i+2] . Slicing is memory-efficient because it doesn't create copies of the original list.


1 Answers

This page shows how to implement a sliding window with itertools. http://docs.python.org/release/2.3.5/lib/itertools-example.html

def window(seq, n=2):
    "Returns a sliding window (of width n) over data from the iterable"
    "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
    it = iter(seq)
    result = tuple(islice(it, n))
    if len(result) == n:
        yield result    
    for elem in it:
        result = result[1:] + (elem,)
        yield result

Example output:

>>> list(window(range(10)))
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]

You'd need to change it to fill left and right if you need.

like image 123
FogleBird Avatar answered Oct 13 '22 00:10

FogleBird