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'
473
demandé sur rushi 2009-01-11 15:34:43

18 réponses

si vous normalisez déjà les entrées aux booléens, alors != est xor.

bool(a) != bool(b)
928
répondu A. Coady 2009-01-11 16:30:46

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)

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

368
répondu Zach Hirsch 2009-01-11 12:35:51

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

from operator import xor
xor(bool(a), bool(b))
131
répondu singingwolfboy 2012-06-14 15:34:09

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".
32
répondu ddaa 2017-05-23 12:18:24
  • Python logical or : A or B : retourne A si bool(A) est True , sinon retourne B
  • Python logique and : A and B : renvoie A si bool(A) est False , sinon renvoie B

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'
22
répondu nosklo 2009-01-11 13:16:02

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
13
répondu Rugnar 2016-02-04 10:42:56

exclusif ou défini comme suit

def xor( a, b ):
    return (a or b) and not (a and b)
7
répondu S.Lott 2009-01-11 13:39:48

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
7
répondu micdah 2010-04-20 14:18:51

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

  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=False=0, alors le résultat serait |0-0|=0=False
  3. si x=True = 1 et y = True=1 alors le résultat serait / 1-1 / =0 = False
  4. si x=False = 0 et y = True=1 alors le résultat serait |0-1 / =1 = True
7
répondu BarocliniCplusplus 2016-08-01 21:57:05

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
6
répondu Markus Jarderot 2009-01-11 15:29:44

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()
5
répondu 2009-07-04 13:58:03

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))
5
répondu Denis Barmenkov 2011-02-10 13:34:36

XOR est implémenté dans operator.xor .

5
répondu lbolla 2012-01-09 11:49:00

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|
  -+-+-+
5
répondu Steve L 2014-03-08 05:11:44

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.

5
répondu Agustin Marcos 2016-05-20 04:25:11

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

4
répondu Marc 2015-07-30 16:30:00

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
3
répondu c z 2017-04-18 15:29:24

nous pouvons facilement trouver xor de deux variables par l'utilisation:

def xor(a,b):
    return a !=b

exemple:

xor (True,False) > > > True

-2
répondu Muhammad Abdullah 2018-01-10 18:35:19