使用any()和all()检查列表是否包含一组值或另一组值

问题描述 投票:0回答:2

我的代码用于井字棋游戏并检查平局状态,但我认为这个问题在一般意义上可能更有用。

我有一个代表董事会的列表,它看起来像这样:

board = [1,2,3,4,5,6,7,8,9]

当玩家移动时,他们移动的整数将被替换为他们的标记(“x”或“o”)。我已经进行了检查以寻找获胜状态。我不能做的是检查平局状态,其中列表值都不是整数,但尚未设置获胜状态。

我目前拥有的代码:

if any(board) != playerOne or any(board) != playerTwo:
    print 'continue'
elif all(board) == playerOne or playerTwo:
    print 'Draw'

if 语句有效,elif 则无效。我认为问题出在我的“或”运算符上。我想检查的是:板上的每个项目是否是

playerOne
标记或
playerTwo
标记。如果我要编写代码:

elif all(board) == playerOne or all(board) == playerTwo:

我会检查棋盘上的每个位置是否都是

playerOne
,或者棋盘上的每个位置都是
playerTwo
,但事实并非如此。

那么如何检查棋盘是否被

playerOne
标记和
playerTwo
标记组合占据?

python list set any
2个回答
180
投票

一般来说:

all
any
是接受一些可迭代对象并返回
True
、if

的函数
  • all
    的情况下,迭代中的 没有值falsy;
  • any
    的情况下,至少有一个 值为 truthy

x
是假值当且仅当
bool(x) == False
。 值
x
为真,当且仅当
bool(x) == True

可迭代中的任何非布尔元素都是完全可以接受的 -

bool(x)
映射,或强制,任何
x
根据这些规则:

  • 0
    0.0
    None
    []
    ()
    []
    set()
    等空集合映射到
    False
  • 所有其他值都映射到
    True

bool
的文档字符串使用术语 'true'/'false' 表示 'truthy'/'falsy',并使用
True
/
False
表示具体的布尔值。


在您的具体代码示例中:

您稍微误解了这些功能的工作原理。以下所做的事情与您的想法完全不同:

if any(foobars) == big_foobar:

...因为

any(foobars)
首先会被评估为
True
False
,然后将该布尔值与
big_foobar
进行比较,这通常总是给你
False
(除非
big_foobar
巧合地发生)为相同的布尔值)。

注意:迭代器可以是列表,但也可以是生成器或生成器表达式(≈延迟计算/生成列表),或任何其他迭代器。

你想要的是:

if any(x == big_foobar for x in foobars):

它基本上首先构造一个生成布尔值序列的迭代器 - 对于

foobars
中的每个项目,它将该项目与
big_foobar
保存的值进行比较,并(惰性地)将生成的布尔值发送到生成的布尔值序列中:

tmp = (x == big_foobar for x in foobars)

然后

any
遍历
tmp
中的所有项目,并在找到第一个真实元素后立即返回
True
。就好像您执行了以下操作:

In [1]: foobars = ['big', 'small', 'medium', 'nice', 'ugly']                                        

In [2]: big_foobar = 'big'                                                                          

In [3]: any(['big' == big_foobar, 'small' == big_foobar, 'medium' == big_foobar, 'nice' == big_foobar, 'ugly' == big_foobar])        
Out[3]: True

注意: 正如 DSM 所指出的,

any(x == y for x in xs)
相当于
y in xs
,但后者更具可读性,写入速度更快,运行速度更快。

一些例子:

In [1]: any(x > 5 for x in range(4))
Out[1]: False

In [2]: all(isinstance(x, int) for x in range(10))
Out[2]: True

In [3]: any(x == 'Erik' for x in ['Erik', 'John', 'Jane', 'Jim'])
Out[3]: True

In [4]: all([True, True, True, False, True])
Out[4]: False

另请参阅:http://docs.python.org/2/library/functions.html#all


0
投票

对于标题中的问题:

如果列表包含一组值或另一组值

使用集合运算可能更自然。换句话说,而不是

if any(x==playerOne for x in board) or any(x==playerTwo for x in board):

# or 
if playerOne in board or playerTwo in board:

使用

set.issubset
(或
set.intersection
1):

if {playerOne, playerTwo}.issubset(board):

# or
if {playerOne, playerTwo} & set(board):

如果

playerOne
playerTwo
是值的集合/列表/元组,则计算它们的并集并测试它是否是
board
的子集:

if {*playerOne,*playerTwo}.issubset(board):

如果问题是

如果板上的每个项目都是playerOne标记或playerTwo标记

然后代替

if all(x == playerOne or x == playerTwo for x in board):

测试集相等:1

if {playerOne, playerTwo} == set(board):

1 显然,您可以预先将

set(board)
分配给某个变量,这样您就不必每次需要测试此条件时都将
board
转换为集合。

© www.soinside.com 2019 - 2024. All rights reserved.