Comment obtenir le XOR logique de deux variables en Python?
Comment obtenir 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 vraie valeur (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 bitwise, 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'
18 réponses
si vous normalisez déjà les entrées aux booléens, alors != est xor.
bool(a) != bool(b)
vous pouvez toujours utiliser la définition de xor pour le calculer à partir d'autres opérations logiques:
(a and not b) or (not a and b)
mais c'est un peu trop verbeux pour moi, et n'est pas particulièrement clair à première vue. Une autre façon de le faire est:
bool(a) ^ bool(b)
l'opérateur xor sur deux booléens est XOR logique (contrairement à l'ints, où il est bitwise). Ce qui a du sens, puisque bool
est juste une sous-classe de int
, mais est mis en œuvre pour avoir seulement les valeurs 0
et 1
. Et XOR logique est équivalent à XOR bitwise lorsque le domaine est limité à 0
et 1
.
donc la fonction logical_xor
serait implémentée comme:
def logical_xor(str1, str2):
return bool(str1) ^ bool(str2)
ou-Exclusif est déjà intégré à Python, dans le operator
module:
from operator import xor
xor(bool(a), bool(b))
comme Zach expliqué, vous pouvez utiliser:
xor = bool(a) ^ bool(b)
personnellement, je préfère un dialecte légèrement différent:
xor = bool(a) + bool(b) == 1
ce dialecte est inspiré d'un langage de schéma logique que j'ai appris à l'école où" ou "a été dénoté par une boîte contenant ≥1
(supérieur ou égal à 1) et" XOR "a été dénoté par une boîte contenant =1
.
Cela a l'avantage de correctement mise en œuvre exclusive ou sur plusieurs opérandes.
- " 1 = A ^ b ^ C..."le nombre de vrai opérandes est impair. Cet opérateur est "parité".
- " 1 = A + b + C..."signifie exactement qu'un opérande est vrai. C'est le "ou exclusif", qui signifie "l'un à l'exclusion des autres".
- Python logical
or
:A or B
: retourneA
sibool(A)
estTrue
, sinon retourneB
- Python logique
and
:A and B
: renvoieA
sibool(A)
estFalse
, sinon renvoieB
pour garder la plupart de cette façon de penser, ma définition XOR logique serait:
def logical_xor(a, b):
if bool(a) == bool(b):
return False
else:
return a or b
comme ça 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)
semble ê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
exclusif ou défini comme suit
def xor( a, b ):
return (a or b) and not (a and b)
comme je ne vois pas la variante simple de xor en utilisant des arguments variables et seulement une opération sur les valeurs de vérité vrai ou faux, je vais juste le jeter ici pour n'importe qui à utiliser. C'est comme indiqué par d'autres, assez (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'usage est simple aussi bien:
if xor(False, False, True, False):
print "Hello World!"
comme c'est le N-ary XOR logique généralisé, sa valeur de vérité sera vraie chaque fois que le nombre de véritables opérandes est impair (et pas seulement quand exactement un est vrai, ce n'est qu'un cas dans lequel n-ary XOR est vrai).
ainsi si vous êtes à la recherche d'un prédicat n-ary qui est seulement vrai quand exactement un de ses opérandes est, vous pourriez vouloir utiliser:
def isOne(*vars):
sum = bool(False)
for v in vars:
if sum and v:
return False
else:
sum = sum or v
return sum
je sais que c'est en retard, mais j'ai eu une pensée et cela pourrait valoir la peine, juste pour la documentation. Peut-être cela fonctionnerait: np.abs(x-y)
l'idée est que
- si x = True=1 et y = False=0 alors le résultat serait |1-0 / =1 = True
- si x=Faux=0 et y=False=0, alors le résultat serait |0-0|=0=False
- si x=True = 1 et y = True=1 alors le résultat serait / 1-1 / =0 = False
- si x=False = 0 et y = True=1 alors le résultat serait |0-1 / =1 = True
et ç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 provoqueront dans certains cas des évaluations répétées des opérandes, ce qui peut conduire à des effets secondaires involontaires et doit donc être évité.
qui dit, une implémentation xor
qui renvoie soit True
ou False
est assez simple; une implémentation qui renvoie l'un des opérandes, si possible, est beaucoup plus délicate, parce qu'il n'y a pas de consensus sur l'opérande qui devrait être choisie, surtout quand il y a plus de deux opérandes. Par exemple, xor(None, -1, [], True)
devrait-il retourner None
, []
ou False
? Je parie que chaque réponse apparaît à certains comme la plus intuitive.
pour le vrai - ou le faux-résultat, il y a cinq choix possibles: retourner le premier opérande (si elle correspond au résultat final en valeur, sinon booléen), retourner le premier match (si au moins un existe, sinon booléen), retourner le dernier opérande (si ... autre. ..), le retour du dernier match (si ... autre. ..), ou de toujours renvoyer un booléen. Au total, c'est 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 on sait ce que fait XOR:
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))
Parfois je me retrouve à travailler avec 1 et 0 au lieu de valeurs vraies et fausses booléennes. 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|
-+-+-+
fil rouge:
anoder idea... Juste vous essayez l'expression (peut-être) pythonic "is not" afin d'obtenir le 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 chaîne:
>>> "abc" is not ""
True
>>> 'abc' is not 'abc'
False
>>> 'abc' is not ''
True
>>> '' is not 'abc'
True
>>> '' is not ''
False
>>>
cependant; comme ils ont indiqué ci-dessus, il dépend du comportement réel que vous voulez tirer sur des chaînes de couple, parce que les chaînes ne sont pas des boléens... et même lire la suite: si vous "plongez en Python" vous trouverez "la nature particulière de" et " et " ou"" http://www.diveintopython.net/power_of_introspection/and_or.html
Désolé mon anglais tordu, ce n'est pas ma langue natale.
Cordialement.
cela obtient l'exclusivité XOR logique 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 avec cette configuration est qu'elle traverse probablement toute la liste deux fois et, au minimum, vérifiera au moins un des éléments deux fois. Donc, il peut augmenter la compréhension du code, mais il ne prête pas à la vitesse (qui peut différer négligemment selon votre cas d'utilisation).
Le deuxième problème de cette configuration est qu'elle vérifie exclusivité quel que soit le nombre de variables. C'est peut être d'abord considérée comme un élément, mais le premier problème devient beaucoup plus important que le nombre de variables augmente (si jamais ils le font).
Simple, facile à comprendre:
sum( (bool(a), bool(b) ) == 1
si un choix exclusif est ce que vous recherchez, il peut être étendu à plusieurs arguments:
sum( bool(x) for x in y ) == 1
nous pouvons facilement trouver xor de deux variables par l'utilisation:
def xor(a,b):
return a !=b
exemple:
xor (True,False) > > > True