Python usa any () y all () para verificar si una lista contiene un conjunto de valores u otro

Mi código es para un juego de Tic Tac Toe y para verificar el estado de un sorteo, pero creo que esta pregunta podría ser más útil en un sentido general.

Tengo una lista que representa el tablero, se parece a esto:

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

Cuando un jugador hace un movimiento, el int en el que se movió es reemplazado por su marcador (‘x’ o ‘o’), ya tengo cheques en su lugar para buscar un estado ganador, lo que no puedo hacer es verificar un empate estado, donde ninguno de los valores de la lista es ints pero no se ha establecido un estado ganador.

El código que tengo hasta ahora:

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

La statement if funciona, el elif no, creo que el problema es mi ‘o’ operador, lo que quiero verificar es: si cada elemento del tablero es un marcador playerOne o playerTwo, si el lugar donde debo hacer el código:

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

Estaría revisando para ver si cada lugar en el tablero era jugador. Uno o cada lugar en el tablero es jugador dos, lo que no será.

Entonces, ¿cómo verifico si el tablero está ocupado por una combinación de marcadores playerOne y playerTwo?

all y any son funciones que toman un iterable y determinan …

  • … en el caso de all() : si todos los valores en ese iterable no son False ;
  • … en el caso de any() : si alguno de los valores en ese iterable no es False .

Las definiciones anteriores también tienen sentido en el caso de un iterable vacío, de lo contrario, se podría decir de manera más natural que all ven si todos los valores son verdaderos, y any ve si algún valor es verdadero.


Entonces, malinterpretaste un poco cómo funcionan estas funciones. Por lo tanto, lo siguiente hace algo completamente distinto a lo que pensabas:

 if any(foobars) == big_foobar: 

… porque any(foobars) primero se evaluaría como True o False , y luego ese valor booleano se compararía con big_foobar , que generalmente siempre le da False (a menos que big_foobar tenga el mismo valor booleano).

Nota: el iterable puede ser una lista, pero también puede ser una expresión de generador / generador (list lista perezosamente evaluada / generada) o cualquier otro iterador.

Lo que quieres en cambio es:

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

que básicamente construye primero un iterable que produce una secuencia de valores booleanos: para cada elemento en foobars , compara el elemento con big_foobar y emite el resultado booleano a la secuencia resultante:

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

luego, any recorre todos los elementos en tmp y devuelve True tan pronto como encuentra el primer elemento True . Es como si hicieras lo siguiente:

 foobars = ['big', 'small', 'medium', 'nice', 'ugly'] big_foobar = 'big' any(['big' == big_foobar, 'small' == big_foobar, 'medium' == big_foobar, ...]) 

Nota: Como señaló DSM, any(x == y for x in xs) es equivalente a y in xs pero este último es más legible, más rápido de escribir y se ejecuta más rápido.

Algunos ejemplos:

 any(x > 5 for x in range(4)) # => False all(isinstance(x, int) for x in range(10)) # => True any(x == 'Erik' for x in ['Erik', 'John', 'Jane', 'Jim']) # => True all([True, True, True, False, True]) # => False 

Le sugiero que simplemente juegue con any y all entradas en el shell de Python, o mejor aún, en el shell de IPython para tener una idea de cómo funciona esto antes de continuar escribiendo el código real.

Consulte también: http://docs.python.org/2/library/functions.html#all