Question Comment obtenez-vous le xor logique de deux variables en Python?


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"

le ^ 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'

462
2018-01-11 12:34


origine


Réponses:


Si vous êtes déjà en train de normaliser les entrées pour les booléens, alors! = Est xor.

bool(a) != bool(b)

895
2018-01-11 16:30



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 ce 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 logique xor (contrairement à ints, où c'est bitwise). Ce qui est logique, 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 bitwise lorsque le domaine est restreint à 0 et 1.

Alors le logical_xor La fonction serait implémentée comme:

def logical_xor(str1, str2):
    return bool(str1) ^ bool(str2)

Crédit à Nick Coghlan sur la liste de diffusion Python-3000.


358
2018-01-11 12:35



Exclusif - ou est déjà intégré à Python, dans le operator module:

from operator import xor
xor(bool(a), bool(b))

126
2018-06-14 15:34



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 est inspiré d'un langage de schématisation logique que j'ai appris à l'école où "OU" était indiqué par une boîte contenant ≥1 (supérieur ou égal à 1) et "XOR" a été indiqué par une boîte contenant =1.

Ceci a l'avantage d'implémenter correctement des opérandes exclusifs ou multiples.

  • "1 = a ^ b ^ c ..." signifie que le nombre d'opérandes vrais est impair. Cet opérateur est "parité".
  • "1 = a + b + c ..." signifie exactement qu'un opérande est vrai. Ceci est "exclusif ou", ce qui signifie "l'un à l'exclusion des autres".

32
2018-01-11 13:44



  • Python logique or: A or B: résultats A si bool(A) est True, sinon retourne B
  • Python logique and: A and B: résultats A si bool(A) est False, sinon retourne B

Pour garder 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 revenir a, b, ou False:

>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'

22
2018-01-11 13:10



J'ai testé plusieurs approches et not a != (not b) semblait être le 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

11
2018-02-04 10:42



Exclusif Ou est défini comme suit

def xor( a, b ):
    return (a or b) and not (a and b)

7
2018-01-11 13:39



Comme je ne vois pas la variante simple de xor en utilisant des arguments variables et que seule l'opération sur les valeurs de vérité est vraie ou fausse, je vais juste la lancer 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 également simple:

if xor(False, False, True, False):
    print "Hello World!"

Comme il s'agit du XOR logique généralisé n-aire, sa valeur de vérité sera Vrai chaque fois que le nombre d'opérandes vrais est impair (et pas seulement quand un est vrai, ce n'est qu'un cas où n-aire XOR est vrai).

Ainsi, si vous êtes à la recherche d'un prédicat n-aire qui est uniquement vrai lorsque l'un de ses opérandes est exact, vous pouvez utiliser:

def isOne(*vars):
    sum = bool(False)
    for v in vars:
        if sum and v:
            return False
        else:
            sum = sum or v
    return sum

7
2018-04-20 13:21



Je sais que c'est tard, mais j'avais une pensée et cela pourrait valoir la peine, juste pour la documentation. Peut-être que cela fonctionnerait:np.abs(x-y)L'idée est que

  1. si x = True = 1 et y = False = 0 alors le résultat serait | 1-0 | = 1 = True
  2. si x = Faux = 0 et y = Faux = 0 alors le résultat serait | 0-0 | = 0 = Faux
  3. si x = True = 1 et y = True = 1 alors le résultat serait | 1-1 | = 0 = Faux
  4. si x = Faux = 0 et y = Vrai = 1 alors le résultat serait | 0-1 | = 1 = Vrai

7
2017-08-01 21:57



Que dis-tu de ça?

(not b and a) or (not a and b)

va donner a si b c'est faux
va donner b si a c'est faux
va donner False autrement

Ou avec l'expression ternaire Python 2.5+:

(False if a else b) if b else a

6
2018-01-11 15:29



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 imprévus et doit donc être évité.

Cela dit, un xor la mise en œuvre qui renvoie 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'y a pas de consensus sur l'opérande qui doit être choisi, surtout lorsqu'il y a plus de deux opérandes. Par exemple, devrait xor(None, -1, [], True) revenir None, [] ou False? Je parie que chaque réponse apparaît à certaines personnes comme la plus intuitive.

Pour le résultat True ou False, il y a jusqu'à cinq choix possibles: return premier opérande (s'il correspond au résultat final en valeur, sinon booléen), retourne la première correspondance (si au moins une existe, sinon booléen), retourne le dernier opérande (if ... else ...), renvoie la dernière correspondance (if ... else ...), ou retourne toujours 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()

5
2017-07-04 09:01