Question Comment tester plusieurs variables par rapport à une valeur?


J'essaye de faire une fonction qui comparera plusieurs variables à un entier et produira une chaîne de trois lettres. Je me demandais s'il y avait un moyen de traduire cela en Python. Dites donc:

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")

qui retournerait une liste de

["c", "d", "f"]

Est-ce que quelque chose comme ça est possible?


414
2018-02-27 12:26


origine


Réponses:


Vous vous méprenez sur le fonctionnement des expressions booléennes; ils ne fonctionnent pas comme une phrase anglaise et supposent que vous parlez de la même comparaison pour tous les noms ici. Tu recherches:

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

x et y sont par ailleurs évalués par eux-mêmes (False si 0, True autrement).

Vous pouvez raccourcir cela en utilisant un test de confinement contre un tuple:

if 1 in (x, y, z):

ou mieux encore:

if 1 in {x, y, z}:

en utilisant une set pour profiter du test d'adhésion à coût constant (in prend un temps fixe quel que soit l'opérande de gauche).

Lorsque vous utilisez or, Python voit chaque côté de l'opérateur comme séparé expressions. L'expression x or y == 1 est traité comme un premier test booléen pour x, alors si c'est False, l'expression y == 1 est testé.

Cela est dû à priorité de l'opérateur. le or l'opérateur a une priorité inférieure à la == test, donc ce dernier est évalué premier.

Cependant, même si c'était ne pas le cas et l'expression x or y or z == 1 a été effectivement interprété comme (x or y or z) == 1 Au lieu de cela, cela ne ferait toujours pas ce que vous attendez de lui.

x or y or z évaluerait le premier argument qui est «véridique», par ex. ne pas False, numérique 0 ou vide (voir expressions booléennes pour plus de détails sur ce que Python considère comme faux dans un contexte booléen).

Donc pour les valeurs x = 2; y = 1; z = 0, x or y or z serait résolu à 2, parce que c'est la première valeur vraie dans les arguments. alors 2 == 1 serait False, même si y == 1 serait True.

La même chose s'appliquerait à l'inverse; tester plusieurs valeurs par rapport à une seule variable; x == 1 or 2 or 3 échouerait pour les mêmes raisons. Utilisation x == 1 or x == 2 or x == 3 ou x in {1, 2, 3}.


553
2018-02-27 12:27



Votre problème est plus facilement résolu avec une structure de dictionnaire comme:

x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]

52
2017-07-11 21:56



Solution précédente: Comme l’a déclaré Martijn Pieters, le format correct et le plus rapide est le suivant:

if 1 in {x, y, z}:

Le principal problème qui ne semble pas être résolu est que vous voulez que votre liste de résultats inclue chaque lettre après une déclaration true.

En utilisant seulement les conseils de Martijn Pieters, vous auriez maintenant:

if 0 in {x, y, z}:
    Mylist.append("c")
elif 1 in {x, y, z}:
    Mylist.append("d")
...

Problème: La première instruction if renverrait la valeur true, et vous n'obtiendriez jamais l'instruction elif suivante. Donc, votre liste reviendrait simplement:

["c"]

Ce que vous voulez, c'est avoir des instructions if séparées pour que python lise chaque instruction, que les premières soient vraies ou fausses. Tel que:

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")
...

Cela fonctionnera, mais si vous êtes à l'aise avec les dictionnaires (voyez ce que je fais là), vous pouvez le nettoyer en créant un dictionnaire initial qui mappe les nombres aux lettres souhaitées, puis en utilisant simplement une boucle 'for':

numToLetters = {0:"c", 1:"d", 2:"e", 3:"f"}
for number in numToLetters:
    if number in {x, y, z}:
        Mylist.append(numToLetters[number])

30
2017-08-19 02:34



La manière directe d'écrire x or y or z == 0 est

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

Mais je ne pense pas, tu aimes ça. :) Et cette voie est laide.

L'autre moyen (un meilleur) est:

0 in (x, y, z)

BTW beaucoup de ifs pourrait être écrit comme quelque chose comme ça

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

21
2017-07-11 21:16



Si vous êtes très paresseux, vous pouvez mettre les valeurs dans un tableau. Tel que

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

Vous pouvez également mettre les chiffres et les lettres dans un dictionnaire et le faire, mais c'est probablement beaucoup plus compliqué que simplement des déclarations. C'est ce que vous obtenez pour essayer d'être plus paresseux :)

Encore une chose, votre

if x or y or z == 0:

compilera, mais pas de la façon dont vous le souhaitez. Lorsque vous mettez simplement une variable dans une instruction if (exemple)

if b

le programme vérifiera si la variable n'est pas nulle. Une autre façon d'écrire la déclaration ci-dessus (qui a plus de sens) est

if bool(b)

Bool est une fonction intégrée dans python qui fait essentiellement la commande de vérifier une instruction booléenne (Si vous ne savez pas ce que c'est, c'est ce que vous essayez de faire dans votre instruction if en ce moment :))

Un autre moyen paresseux que j'ai trouvé est:

if any([x==0, y==0, z==0])

17
2018-05-25 03:53



Pour vérifier si une valeur est contenue dans un ensemble de variables, vous pouvez utiliser les modules intégrés itertools et operator.

Par exemple:

Importations:

from itertools import repeat
from operator import contains

Déclarer les variables:

x = 0
y = 1
z = 3

Créer un mappage des valeurs (dans l'ordre que vous voulez vérifier):

check_values = (0, 1, 3)

Utilisation itertools pour permettre la répétition des variables:

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

Enfin, utilisez le map Fonction pour créer un itérateur:

checker = map(contains, check_vars, check_values)

Ensuite, lors de la vérification des valeurs (dans l'ordre d'origine), utilisez next():

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

etc...

Cela a un avantage sur le lambda x: x in (variables) car operator est un module intégré et est plus rapide et plus efficace que l'utilisation lambda qui doit créer une fonction sur place personnalisée.

Une autre option pour vérifier s'il existe une valeur non nulle (ou False) dans une liste:

not (x and y and z)

Équivalent:

not all((x, y, z))

13
2018-06-04 17:09



Set est la bonne approche ici, car elle ordonne les variables, ce qui semble être votre objectif ici. {z,y,x} est {0,1,3} quel que soit l'ordre des paramètres.

>>> ["cdef"[i] for i in {z,x,y}]
['c', 'd', 'f']

De cette façon, la solution complète est O (n).


13
2018-06-09 20:46



Je pense que cela va mieux gérer:

my_dict = {0: "c", 1: "d", 2: "e", 3: "f"}

def validate(x, y, z):
    for ele in [x, y, z]:
        if ele in my_dict.keys():
            return my_dict[ele]

Sortie:

print validate(0, 8, 9)
c
print validate(9, 8, 9)
None
print validate(9, 8, 2)
e

12
2018-01-13 12:10



Si vous voulez utiliser if, else, les instructions suivantes sont une autre solution:

myList = []
aList = [0,1,3]

for l in aList:
    if l==0:myList.append('c')
    elif l==1:myList.append('d')
    elif l==2:myList.append('e')
    elif l==3:myList.append('f')

print(myList)

12
2018-04-10 03:29



Toutes les excellentes réponses fournies ici se concentrent sur l'exigence spécifique de l'affiche originale et se concentrent sur la if 1 in {x,y,z} solution proposée par Martijn Pieters.
Ce qu'ils ignorent est l'implication plus large de la question:
Comment tester une variable par rapport à plusieurs valeurs?
La solution fournie ne fonctionnera pas pour les hits partiels si vous utilisez des chaînes, par exemple:
Tester si la chaîne "Wild" est dans plusieurs valeurs

>>> x="Wild things"
>>> y="throttle it back"
>>> z="in the beginning"
>>> if "Wild" in {x,y,z}: print (True)
... 

ou

>>> x="Wild things"
>>> y="throttle it back"
>>> z="in the beginning"
>>> if "Wild" in [x,y,z]: print (True)
... 

pour ce scénario, il est plus facile de convertir en une chaîne

>>> [x,y,z]
['Wild things', 'throttle it back', 'in the beginning']
>>> {x,y,z}
{'in the beginning', 'throttle it back', 'Wild things'}
>>> 

>>> if "Wild" in str([x,y,z]): print (True)
... 
True
>>> if "Wild" in str({x,y,z}): print (True)
... 
True

Il convient de noter cependant, comme mentionné par @codeforester, les limites de ce mot sont perdues avec cette méthode, comme dans:

>>> x=['Wild things', 'throttle it back', 'in the beginning']
>>> if "rot" in str(x): print(True)
... 
True

les 3 lettres rot existent en combinaison dans la liste mais pas en tant que mot individuel. Le test de «pourriture» échouerait mais si l'un des éléments de la liste était «pourrir en enfer», cela échouerait également.
Le résultat étant, soyez prudent avec vos critères de recherche si vous utilisez cette méthode et sachez qu'il a cette limitation.


11
2017-09-10 15:44



d = {0:'c', 1:'d', 2:'e', 3: 'f'}
x, y, z = (0, 1, 3)
print [v for (k,v) in d.items() if x==k or y==k or z==k]

10
2018-02-27 01:31