Search code examples
pythonfunctional-programmingiterator

What is the most pythonic way to exclude a special value from an iterator?


As an example. Lets say I have a grid-based game, where the player agent can walk to all squares around the current position, but not stay still.

Thus we could see each move as a tuple (dx,dy), with the total set of moves being [(1,1), (1,0), (1,-1), (0,1), (0,-1), (-1,1), (-1,0), (-1,-1)] Staying still would be (dx,dy) = (0,0).

With this problem in mind, one could make use of the cartesian product of [1,0,-1] with itself, which in Python would be itertools.product(iterables*). However, this would yield all those tuples listed above, including (0,0)

One solution is to convert it to a list, and then use remove() on the list:

steps = list(itertools.product([-1,0,1],[-1,0,1])).remove((0,0)) or alternatively [x for x in itertools.product([1,0,-1], [1,0,-1]) if x != (0,0)]. Both of these solutions require conversion to lists.

What's your cleanest way to yield and exclude (0,0)?


Solution

  • Generally speaking you would define another iterator based on the first one and apply a condition in a comprehension.

    In this case:

    moves = ( p for p in itertools.product((-1,0,1),repeat=2) if p != (0,0) )
    

    Here moves is a new generator that will filter out (0,0) from the output of itertools.product. Notice that it is enclosed in parentheses, not square brackets which would make it a list instead of an iterator