Comment obtenez-vous le xor logique de deux variables en Python?
Par exemple, j'ai deux variables que je m'attends à être des chaînes. Je veux tester qu'un seul d'entre eux contient une valeur True (n'est pas None ou la chaîne vide):
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
if logical_xor(str1, str2):
print "ok"
else:
print "bad"
L'opérateur ^
semble être au niveau du bit, et non défini sur tous les objets:
>>> 1 ^ 1
0
>>> 2 ^ 1
3
>>> "abc" ^ ""
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ^: 'str' and 'str'
Si vous normalisez déjà les entrées en booléens, alors! = Est xor.
bool(a) != bool(b)
Vous pouvez toujours utiliser la définition de xor pour la calculer à partir d'autres opérations logiques:
(a and not b) or (not a and b)
Mais ceci est un peu trop verbeux pour moi et n'est pas particulièrement clair au premier abord. Une autre façon de le faire est:
bool(a) ^ bool(b)
L'opérateur xor sur deux booléens est xor logique (contrairement aux entiers, où il est au niveau des bits). Ce qui a du sens, puisque bool
EST JUSTE UNE SOUS-CLASSE DE int
, mais est implémenté pour n’avoir que les valeurs 0
et 1
. Et xor logique est équivalent à xor au niveau du bit lorsque le domaine est limité à 0
et 1
.
Ainsi, la fonction logical_xor
serait implémentée comme suit:
def logical_xor(str1, str2):
return bool(str1) ^ bool(str2)
Nous remercions Nick Coghlan de la liste de diffusion Python-30 .
Bitwise exclusive-or est déjà intégré à Python, dans le module operator
(identique au module ^
opérateur):
from operator import xor
xor(bool(a), bool(b)) # Note: converting to bools is essential
Comme Zach expliqué, vous pouvez utiliser:
xor = bool(a) ^ bool(b)
Personnellement, je privilégie un dialecte légèrement différent:
xor = bool(a) + bool(b) == 1
Ce dialecte s’inspire d’un langage logique que j’ai appris à l’école où "OR" était désigné par une boîte contenant ≥1
(supérieur ou égal à 1) et "XOR" par une boîte contenant =1
.
Cela présente l’avantage d’implémenter correctement des opérandes exclusifs ou multiples.
or
: A or B
: renvoie A
si bool(A)
est True
, sinon renvoie B
and
: A and B
: renvoie A
si bool(A)
est False
, sinon renvoie B
Pour conserver la plus grande partie de cette façon de penser, ma définition logique serait:
def logical_xor(a, b):
if bool(a) == bool(b):
return False
else:
return a or b
De cette façon, il peut retourner a
, b
ou False
:
>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'
J'ai testé plusieurs approches et not a != (not b)
semblait être la plus rapide.
Voici quelques tests
%timeit not a != (not b)
10000000 loops, best of 3: 78.5 ns per loop
In [130]: %timeit bool(a) != bool(b)
1000000 loops, best of 3: 343 ns per loop
In [131]: %timeit not a ^ (not b)
10000000 loops, best of 3: 131 ns per loop
Fil récompensant:
Idée Anoder ... Vous venez d’essayer l’expression Pythonic (peut-être) "n’est pas" afin d’obtenir un comportement de "xor" logique
La table de vérité serait:
>>> True is not True
False
>>> True is not False
True
>>> False is not True
True
>>> False is not False
False
>>>
Et pour votre exemple de chaîne:
>>> "abc" is not ""
True
>>> 'abc' is not 'abc'
False
>>> 'abc' is not ''
True
>>> '' is not 'abc'
True
>>> '' is not ''
False
>>>
Pourtant; comme indiqué ci-dessus, cela dépend du comportement réel que vous souhaitez adopter à propos de quelques chaînes, car elles ne sont pas des boleans ... et plus encore: si vous "plongez au cœur de Python", vous découvrirez "La nature particulière de" et "et" ou "" http://www.diveintopython.net/power_of_introspection/and_or.html
Désolé mon anglais écrit, ce n'est pas ma langue d'origine.
Cordialement.
Je sais que c'est tard, mais j'avais une idée et ça valait peut-être la peine, juste pour la documentation. Cela fonctionnerait peut-être: np.abs(x-y)
L'idée est que
Exclusive Or est défini comme suit
def xor( a, b ):
return (a or b) and not (a and b)
Simple, facile à comprendre:
sum( (bool(a), bool(b) ) == 1
Si vous recherchez un choix exclusif, vous pouvez l'étendre à plusieurs arguments:
sum( bool(x) for x in y ) % 2 == 1
Comme je ne vois pas la simple variante de xor utilisant des arguments variables et uniquement une opération sur les valeurs de vérité Vrai ou Faux, je le jetterai ici pour que tout le monde l’utilise. C'est comme noté par d'autres, joli (pour ne pas dire très) simple.
def xor(*vars):
sum = bool(False)
for v in vars:
sum = sum ^ bool(v)
return sum
Et l’utilisation est aussi simple:
if xor(False, False, True, False):
print "Hello World!"
Comme il s'agit du XOR logique n-aire généralisé, sa valeur de vérité sera True chaque fois que le nombre d'opérandes True sera impair (et pas seulement lorsqu'un seul est vrai, il s'agit simplement d'un cas dans lequel n-ary XOR est vrai).
Ainsi, si vous êtes à la recherche d'un prédicat n-aire qui n'est vrai que lorsque exactement l'un de ses opérandes l'est, vous voudrez peut-être utiliser:
def isOne(*vars):
sum = bool(False)
for v in vars:
if sum and v:
return False
else:
sum = sum or v
return sum
Parfois, je me retrouve à travailler avec 1 et 0 au lieu de valeurs booléennes Vrai et Faux. Dans ce cas, xor peut être défini comme
z = (x + y) % 2
qui a la table de vérité suivante:
x
|0|1|
-+-+-+
0|0|1|
y -+-+-+
1|1|0|
-+-+-+
Que dis-tu de ça?
(not b and a) or (not a and b)
donnera a
si b
est faux
donnera b
si a
est faux
donnera False
sinon
Ou avec l'expression Python 2.5 + ternaire:
(False if a else b) if b else a
Certaines des implémentations suggérées ici entraîneront une évaluation répétée des opérandes dans certains cas, ce qui peut entraîner des effets secondaires non souhaités et doit donc être évité.
Cela dit, une implémentation de xor
qui retourne soit True
ou False
est assez simple; celui qui retourne l'un des opérandes, si possible, est beaucoup plus délicat, car il n'existe pas de consensus sur l'opérande choisi, en particulier lorsqu'il y a plus de deux opérandes. Par exemple, xor(None, -1, [], True)
doit-il renvoyer None
, []
ou False
? Je parie que chaque réponse apparaît à certains comme la plus intuitive.
Il existe cinq choix possibles pour le résultat True ou le résultat False: renvoyer le premier opérande (s'il correspond au résultat final, sinon valeur booléenne), renvoyer la première correspondance (si au moins un existe, sinon valeur booléenne), retourne le dernier opérande (si ... sinon ...), retourne le dernier match (si ... autre ...), ou retourne toujours un booléen. Au total, cela fait 5 ** 2 = 25 saveurs de xor
.
def xor(*operands, falsechoice = -2, truechoice = -2):
"""A single-evaluation, multi-operand, full-choice xor implementation
falsechoice, truechoice: 0 = always bool, +/-1 = first/last operand, +/-2 = first/last match"""
if not operands:
raise TypeError('at least one operand expected')
choices = [falsechoice, truechoice]
matches = {}
result = False
first = True
value = choice = None
# avoid using index or slice since operands may be an infinite iterator
for operand in operands:
# evaluate each operand once only so as to avoid unintended side effects
value = bool(operand)
# the actual xor operation
result ^= value
# choice for the current operand, which may or may not match end result
choice = choices[value]
# if choice is last match;
# or last operand and the current operand, in case it is last, matches result;
# or first operand and the current operand is indeed first;
# or first match and there hasn't been a match so far
if choice < -1 or (choice == -1 and value == result) or (choice == 1 and first) or (choice > 1 and value not in matches):
# store the current operand
matches[value] = operand
# next operand will no longer be first
first = False
# if choice for result is last operand, but they mismatch
if (choices[result] == -1) and (result != value):
return result
else:
# return the stored matching operand, if existing, else result as bool
return matches.get(result, result)
testcases = [
(-1, None, True, {None: None}, [], 'a'),
(None, -1, {None: None}, 'a', []),
(None, -1, True, {None: None}, 'a', []),
(-1, None, {None: None}, [], 'a')]
choices = {-2: 'last match', -1: 'last operand', 0: 'always bool', 1: 'first operand', 2: 'first match'}
for c in testcases:
print(c)
for f in sorted(choices.keys()):
for t in sorted(choices.keys()):
x = xor(*c, falsechoice = f, truechoice = t)
print('f: %d (%s)\tt: %d (%s)\tx: %s' % (f, choices[f], t, choices[t], x))
print()
C'est facile quand vous savez ce que XOR fait:
def logical_xor(a, b):
return (a and not b) or (not a and b)
test_data = [
[False, False],
[False, True],
[True, False],
[True, True],
]
for a, b in test_data:
print '%r xor %s = %r' % (a, b, logical_xor(a, b))
Ceci obtient l'exclusivité logique XOR pour deux (ou plus) variables
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
any([str1, str2]) and not all([str1, str2])
Le premier problème de cette configuration est qu’elle parcourt très probablement la totalité de la liste deux fois et vérifie au moins au moins un des éléments deux fois. Donc, cela peut augmenter la compréhension du code, mais cela ne favorise pas la vitesse (qui peut différer de manière négligeable selon votre cas d'utilisation).
Le deuxième problème de cette configuration est qu’elle vérifie l’exclusivité quel que soit le nombre de variables. Cela peut être considéré à l’origine comme une caractéristique, mais le premier problème devient beaucoup plus important à mesure que le nombre de variables augmente (le cas échéant).
Beaucoup de gens, y compris moi-même, ont besoin d'une fonction xor
qui se comporte comme un circuit xor à n entrées, où n est variable. (Voir https://en.wikipedia.org/wiki/XOR_gate ). La fonction simple suivante implémente ceci.
def xor(*args):
"""
This function accepts an arbitrary number of input arguments, returning True
if and only if bool() evaluates to True for an odd number of the input arguments.
"""
return bool(sum(map(bool,args)) % 2)
Exemple d'E/S suit:
In [1]: xor(False, True)
Out[1]: True
In [2]: xor(True, True)
Out[2]: False
In [3]: xor(True, True, True)
Out[3]: True
Xor est ^
en Python. Il retourne:
__xor__
.De toute façon, si vous avez l’intention de les utiliser sur des chaînes, les insérer dans bool
rend votre opération sans ambiguïté (vous pouvez également dire set(str1) ^ set(str2)
).
Python a un opérateur OU exclusif au niveau du bit, c’est ^
:
>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False
Vous pouvez l'utiliser en convertissant les entrées en booléens avant d'appliquer xor (^
):
bool(a) ^ bool(b)
(Edité - merci Arel)
XOR est implémenté dans operator.xor
.
Pour obtenir le xor logique de deux variables ou plus en Python:
^
ou operator.xor
)Par exemple,
bool(a) ^ bool(b)
Lorsque vous convertissez les entrées en valeurs booléennes, au niveau du bit xor devient logique xor.
Notez que la réponse acceptée est fausse:!=
n'est pas identique à xor dans Python en raison de la subtilité de l'enchaînement d'opérateurs .
Par exemple, le xor des trois valeurs ci-dessous est incorrect lorsque vous utilisez !=
:
True ^ False ^ False # True, as expected of XOR
True != False != False # False! Equivalent to `(True != False) and (False != False)`
(P.S. j'ai essayé de modifier la réponse acceptée pour inclure cet avertissement, mais ma modification a été rejetée.)