从迭代器中排除特殊值的最pythonic 方法是什么?

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

举个例子。假设我有一个基于网格的游戏,玩家代理可以走到当前位置周围的所有方块,但不能原地不动。

因此我们可以将每一步视为一个元组 (dx,dy),总步数为 [(1,1), (1,0), (1,-1), (0,1), (0,-1), (-1,1), (-1,0), (-1,-1)] 保持静止将是 (dx,dy) = (0,0).

考虑到这个问题,可以利用 [1,0,-1] 与自身的笛卡尔积,在 Python 中将是 itertools.product(iterables*)。然而,这将产生上面列出的所有那些元组,包括 (0,0)

一种解决方案是将其转换为列表,然后在列表上使用remove()

steps = list(itertools.product([-1,0,1],[-1,0,1])).remove((0,0)) 或者 [x for x in itertools.product([1,0,-1], [1,0,-1]) if x != (0,0)]。这两种解决方案都需要转换为列表。

产生和排除的最干净的方法是什么(0,0)

这个问题可能属于opinion-based的范畴,可以关闭,但最干净的方法是像你已经做的那样严格枚举有效值.明确说明这些值比将它们的生成塞进 one-liner 更具可读性,尤其是当它们看起来是常数时。您甚至可以格式化代码以提高可读性(假设像 black 这样的工具不会影响它)。

VALID_MOVES = (
    (-1, 1), (0, 1), (1, 1),
    (-1, 0),         (1, 0),
    (-1,-1), (0,-1), (1,-1)
)

一般来说,您会在第一个迭代器的基础上定义另一个迭代器,并在理解中应用条件。

在这种情况下:

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

这里moves是一个新的生成器,它将从itertools.product的输出中过滤掉(0,0)。 注意它被括在圆括号中,而不是方括号中,这将使它成为一个列表而不是迭代器