¿Cómo probar la igualdad de múltiples variables frente a un solo valor?

Resuelto user1877442 asked hace 11 años • 31 respuestas

Estoy intentando crear una función que compare varias variables con un número entero y genere una cadena de tres letras. Me preguntaba si había alguna manera de traducir esto a Python. Así que di:

x = 0
y = 1
z = 3
mylist = []

if x or y or z == 0:
    mylist.append("c")
if x or y or z == 1:
    mylist.append("d")
if x or y or z == 2:
    mylist.append("e")
if x or y or z == 3: 
    mylist.append("f")

que devolvería una lista de:

["c", "d", "f"]
user1877442 avatar Feb 27 '13 19:02 user1877442
Aceptado

No entiendes cómo funcionan las expresiones booleanas; no funcionan como una oración en inglés y supongo que estás hablando de la misma comparación para todos los nombres aquí. Estás buscando:

if x == 1 or y == 1 or z == 1:

xy yde lo contrario se evalúan por sí solos ( Falsesi 0, Truede lo contrario).

Puedes acortarlo usando una prueba de contención contra una tupla :

if 1 in (x, y, z):

o mejor aún:

if 1 in {x, y, z}:

usar aset para aprovechar la prueba de membresía de costo constante (es decir, intoma una cantidad de tiempo fija cualquiera que sea el operando de la izquierda).

Explicación

Cuando usas or, Python ve cada lado del operador como expresiones separadas . La expresión x or y == 1se trata primero como una prueba booleana para x, luego, si es False, y == 1se prueba la expresión.

Esto se debe a la precedencia de los operadores . El oroperador tiene una precedencia menor que la ==prueba, por lo que esta última se evalúa primero .

Sin embargo, incluso si este no fuera el caso, y la expresión x or y or z == 1en realidad se interpretara como (x or y or z) == 1tal, esto todavía no haría lo que usted espera que haga.

x or y or zse evaluaría como el primer argumento que sea "verdadero", por ejemplo, not False, numérico 0 o vacío (consulte expresiones booleanas para obtener detalles sobre lo que Python considera falso en un contexto booleano).

Entonces, para los valores x = 2; y = 1; z = 0, x or y or zse resolvería en 2, porque ese es el primer valor verdadero en los argumentos. Entonces 2 == 1sería False, aunque y == 1sería True.

Lo mismo se aplicaría a la inversa; probar múltiples valores contra una sola variable; x == 1 or 2 or 3fracasaría por las mismas razones. Utilice x == 1 or x == 2 or x == 3o x in {1, 2, 3}.

Martijn Pieters avatar Feb 27 '2013 12:02 Martijn Pieters

Su problema se soluciona más fácilmente con una estructura de diccionario como:

x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]
dansalmo avatar Jul 11 '2013 21:07 dansalmo

Como afirma Martijn Pieters, el formato correcto y más rápido es:

if 1 in {x, y, z}:

Siguiendo su consejo, ahora tendría declaraciones if separadas para que Python lea cada declaración, ya sea que las primeras fueran Trueo False. Como:

if 0 in {x, y, z}:
    mylist.append("c")
if 1 in {x, y, z}:
    mylist.append("d")
if 2 in {x, y, z}:
    mylist.append("e")
...

Esto funcionará, pero si te sientes cómodo usando diccionarios (mira lo que hice allí), puedes limpiar esto creando un diccionario inicial que asigne los números a las letras que deseas y luego simplemente usando un bucle for:

num_to_letters = {0: "c", 1: "d", 2: "e", 3: "f"}
for number in num_to_letters:
    if number in {x, y, z}:
        mylist.append(num_to_letters[number])
ThatGuyRussell avatar Aug 19 '2015 02:08 ThatGuyRussell

La forma directa de escribir x or y or z == 0es

if any(map((lambda value: value == 0), (x,y,z))):
    pass # write your logic.

Pero no creo que te guste. :) Y así es feo.

La otra forma (mejor) es:

0 in (x, y, z)

Por cierto, muchos ifs podrían escribirse como algo como esto

my_cases = {
    0: Mylist.append("c"),
    1: Mylist.append("d")
    # ..
}

for key in my_cases:
    if key in (x,y,z):
        my_cases[key]()
        break
akaRem avatar Jul 11 '2013 21:07 akaRem

Si ERES muy vago, puedes poner los valores dentro de una matriz. Como

list = []
list.append(x)
list.append(y)
list.append(z)
nums = [add numbers here]
letters = [add corresponding letters here]
for index in range(len(nums)):
    for obj in list:
        if obj == num[index]:
            MyList.append(letters[index])
            break

También puedes poner los números y letras en un diccionario y hacerlo, pero esto probablemente sea MUCHO más complicado que simplemente declaraciones if. Eso es lo que te pasa por intentar ser muy vago :)

Una cosa más, tu

if x or y or z == 0:

se compilará, pero no de la forma deseada. Cuando simplemente pones una variable en una declaración if (ejemplo)

if b

el programa comprobará si la variable no es nula. Otra forma de escribir la declaración anterior (que tiene más sentido) es

if bool(b)

Bool es una función incorporada en Python que básicamente ejecuta el comando de verificar una declaración booleana (si no sabes qué es eso, es lo que estás intentando hacer en tu declaración if ahora mismo :))

Otra forma perezosa que encontré es:

if any([x==0, y==0, z==0])
rassa45 avatar May 25 '2015 03:05 rassa45

Para comprobar si un valor está contenido dentro de un conjunto de variables, puede utilizar los módulos incorporados itertoolsy operator.

Por ejemplo:

Importaciones:

from itertools import repeat
from operator import contains

Declarar variables:

x = 0
y = 1
z = 3

Cree un mapeo de valores (en el orden que desea verificar):

check_values = (0, 1, 3)

Utilícelo itertoolspara permitir la repetición de las variables:

check_vars = repeat((x, y, z))

Finalmente, use la mapfunción para crear un iterador:

checker = map(contains, check_vars, check_values)

Luego, al verificar los valores (en el orden original), use next():

if next(checker)  # Checks for 0
    # Do something
    pass
elif next(checker)  # Checks for 1
    # Do something
    pass

etc...

Esto tiene una ventaja sobre lambda x: x in (variables)porque operatores un módulo incorporado y es más rápido y eficiente que el uso lambdaque tiene que crear una función personalizada en el lugar.

Otra opción para comprobar si hay un valor distinto de cero (o Falso) en una lista:

not (x and y and z)

Equivalente:

not all((x, y, z))
GuiltyDolphin avatar Jun 04 '2014 17:06 GuiltyDolphin