it-swarm.com.de

Wie erhält man das logische xor zweier Variablen in Python?

Wie erhält man in Python das logisches xor zweier Variablen?

Ich habe beispielsweise zwei Variablen, von denen ich erwarte, dass sie Zeichenfolgen sind. Ich möchte testen, dass nur einer von ihnen einen True-Wert enthält (nicht None oder die leere Zeichenfolge):

str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
if logical_xor(str1, str2):
    print "ok"
else:
    print "bad"

Der Operator ^ scheint bitweise und nicht für alle Objekte definiert zu sein:

>>> 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'
566
Zach Hirsch

Wenn Sie die Eingaben bereits zu Booleschen Werten normalisieren, ist! = Xor.

bool(a) != bool(b)
1069
A. Coady

Sie können die Definition von xor jederzeit verwenden, um sie aus anderen logischen Operationen zu berechnen:

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

Aber das ist mir ein bisschen zu ausführlich und auf den ersten Blick nicht besonders klar. Eine andere Möglichkeit ist:

bool(a) ^ bool(b)

Der Operator xor für zwei Boolesche Werte ist logisch xor (im Gegensatz zu ints, wo es bitweise ist). Was Sinn macht, da bool nur eine Unterklasse von int ist , aber implementiert wird, um nur die Werte 0 und 1 zu haben. Und logisches xor entspricht bitweisem xor, wenn die Domäne auf 0 und 1 beschränkt ist.

Die Funktion logical_xor würde also folgendermaßen implementiert:

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

Dank an Nick Coghlan auf der Python-3000-Mailingliste .

434
Zach Hirsch

Bitweises Exklusiv-oder ist bereits in Python im operator -Modul integriert (identisch mit dem Operator ^) :

from operator import xor
xor(bool(a), bool(b))  # Note: converting to bools is essential
168
singingwolfboy

Wie Zach erklärt, können Sie verwenden:

xor = bool(a) ^ bool(b)

Persönlich bevorzuge ich einen etwas anderen Dialekt:

xor = bool(a) + bool(b) == 1

Dieser Dialekt ist inspiriert von einer logischen Diagrammsprache, die ich in der Schule gelernt habe, als "OR" durch ein Kästchen mit ≥1 (größer oder gleich 1) und "XOR" durch ein Kästchen mit =1.

Dies hat den Vorteil, dass exklusive Operanden oder mehrere Operanden korrekt implementiert werden.

  • "1 = a ^ b ^ c ..." bedeutet, dass die Anzahl der wahren Operanden ungerade ist. Dieser Operator ist "Parität".
  • "1 = a + b + c ..." bedeutet, dass genau ein Operand wahr ist. Dies ist "exklusiv oder" und bedeutet "eins unter Ausschluss der anderen".
38
ddaa
  • Python logisch or: A or B: Gibt A zurück, wenn bool(A)True ist, andernfalls B
  • Python logisch and: A and B: Gibt A zurück, wenn bool(A)False ist, andernfalls B

Um die meisten dieser Denkweisen beizubehalten, wäre meine logische xor-Definition:

def logical_xor(a, b):
    if bool(a) == bool(b):
        return False
    else:
        return a or b

Auf diese Weise kann a, b oder False zurückgegeben werden:

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

Ich habe verschiedene Ansätze getestet und not a != (not b) schien die schnellste zu sein.

Hier sind einige 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
18
Rugnar

Belohnungsfaden:

Anoder Idee ... Probieren Sie einfach den (möglicherweise) pythonischen Ausdruck "nicht" aus, um das Verhalten von logischem "xor" zu erhalten.

Die Wahrheitstabelle wäre:

>>> True is not True
False
>>> True is not False
True
>>> False is not True
True
>>> False is not False
False
>>>

Und für deinen Beispielstring:

>>> "abc" is not  ""
True
>>> 'abc' is not 'abc' 
False
>>> 'abc' is not '' 
True
>>> '' is not 'abc' 
True
>>> '' is not '' 
False
>>> 

Jedoch; Wie oben angegeben, hängt es von dem tatsächlichen Verhalten ab, das Sie in Bezug auf ein paar Zeichenfolgen herausziehen möchten, da Zeichenfolgen keine Boleans sind. und "und" oder "" http://www.diveintopython.net/power_of_introspection/and_or.html

Tut mir leid, mein geschriebenes Englisch ist nicht meine Muttersprache.

Grüße.

8
Agustin Marcos

Ich weiß, dass es spät ist, aber ich hatte einen Gedanken und es könnte sich lohnen, nur zur Dokumentation. Vielleicht würde das funktionieren: np.abs(x-y) Die Idee ist, dass

  1. wenn x = True = 1 und y = False = 0 ist, ist das Ergebnis | 1-0 | = 1 = True
  2. wenn x = Falsch = 0 und y = Falsch = 0 ist, ist das Ergebnis | 0-0 | = 0 = Falsch
  3. wenn x = wahr = 1 und y = wahr = 1, dann wäre das Ergebnis | 1-1 | = 0 = falsch
  4. wenn x = False = 0 und y = True = 1 ist, ist das Ergebnis | 0-1 | = 1 = True
7

Exklusives Oder ist wie folgt definiert

def xor( a, b ):
    return (a or b) and not (a and b)
7
S.Lott

Einfach, leicht zu verstehen:

sum( (bool(a), bool(b) ) == 1

Wenn Sie nach einer exklusiven Auswahl suchen, können Sie diese auf mehrere Argumente erweitern:

sum( bool(x) for x in y ) % 2 == 1
7
c z

Da ich die einfache Variante von x oder die Verwendung variabler Argumente und nur die Operation mit den Wahrheitswerten True oder False nicht sehe, werde ich sie hier nur für jedermann zur Verfügung stellen. Es ist, wie von anderen angemerkt, hübsch (um nicht zu sagen sehr) geradlinig.

def xor(*vars):
    sum = bool(False)
    for v in vars:
        sum = sum ^ bool(v)
    return sum

Auch die Nutzung ist unkompliziert:

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

Da dies das verallgemeinerte n-fache logische XOR ist, ist sein Wahrheitswert immer dann wahr, wenn die Anzahl der wahren Operanden ungerade ist (und nicht nur, wenn genau einer wahr ist, ist dies nur ein Fall, in dem n-fache XOR ist wahr).

Wenn Sie also auf der Suche nach einem n-fachen Prädikat sind, das nur dann True ist, wenn genau einer seiner Operanden ist, möchten Sie möglicherweise Folgendes verwenden:

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

Manchmal arbeite ich mit 1 und 0 anstatt mit den booleschen Werten True und False. In diesem Fall kann xor definiert werden als

z = (x + y) % 2

welches die folgende Wahrheitstabelle hat:

     x
   |0|1|
  -+-+-+
  0|0|1|
y -+-+-+
  1|1|0|
  -+-+-+
6
Steve L

Wie wäre es damit?

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

gibt a, wenn b falsch ist
gibt b, wenn a falsch ist
wird False anders geben

Oder mit dem ternären Ausdruck Python 2.5+:

(False if a else b) if b else a
6
Markus Jarderot

Einige der hier vorgeschlagenen Implementierungen führen in einigen Fällen zu einer wiederholten Auswertung der Operanden, was zu unbeabsichtigten Nebenwirkungen führen kann und daher vermieden werden muss.

Das heißt, eine xor -Implementierung, die entweder True oder False zurückgibt, ist ziemlich einfach; Ein Operand, der nach Möglichkeit einen der Operanden zurückgibt, ist viel kniffliger, da kein Konsens darüber besteht, welcher Operand ausgewählt werden soll, insbesondere wenn mehr als zwei Operanden vorhanden sind. Soll xor(None, -1, [], True) beispielsweise None, [] oder False zurückgeben? Ich wette, jede Antwort erscheint einigen Leuten als die intuitivste.

Für das True- oder das False-Ergebnis gibt es bis zu fünf mögliche Auswahlmöglichkeiten: Rückgabe des ersten Operanden (wenn es mit dem Endergebnis im Wert übereinstimmt, sonst boolesch), Rückgabe der ersten Übereinstimmung (wenn mindestens eine vorhanden ist, sonst boolesch), Letzten Operanden zurückgeben (falls ... sonst ...), letzte Übereinstimmung zurückgeben (falls ... sonst ...) oder immer Booleschen Wert zurückgeben. Insgesamt sind das 5 ** 2 = 25 Geschmacksrichtungen von 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()
6

Es ist einfach, wenn Sie wissen, was XOR tut:

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))
4
Denis Barmenkov

Dies liefert das logische Exklusiv XOR für zwei (oder mehr) Variablen

str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")

any([str1, str2]) and not all([str1, str2])

Das erste Problem bei diesem Setup ist, dass es höchstwahrscheinlich die gesamte Liste zweimal durchläuft und mindestens eines der Elemente zweimal überprüft. Dadurch wird zwar das Codeverständnis verbessert, jedoch nicht die Geschwindigkeit (die je nach Anwendungsfall geringfügig abweichen kann).

Das zweite Problem bei dieser Konfiguration besteht darin, dass unabhängig von der Anzahl der Variablen auf Exklusivität geprüft wird. Dies kann zunächst als ein Merkmal angesehen werden, aber das erste Problem wird umso bedeutender, je mehr Variablen vorhanden sind (falls dies jemals der Fall ist).

4
Marc

Viele Leute, einschließlich ich, benötigen eine xor -Funktion, die sich wie eine xor-Schaltung mit n Eingängen verhält, wobei n variabel ist. (Siehe https://en.wikipedia.org/wiki/XOR_gate ). Die folgende einfache Funktion implementiert dies.

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)

Beispiel I/O folgt:

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
4

Xor ist ^ in Python. Es gibt zurück:

  • Ein bitweises xor für ints
  • Logisches xor für Narren
  • Eine exklusive Union für Sets
  • Benutzerdefinierte Ergebnisse für Klassen, die __xor__ implementieren.
  • TypeError für undefinierte Typen, z. B. Zeichenfolgen oder Wörterbücher.

Wenn Sie sie trotzdem für Zeichenfolgen verwenden möchten, wird Ihre Operation durch das Umsetzen in bool eindeutig (Sie könnten auch set(str1) ^ set(str2) bedeuten).

4
Arthur Havlicek

Python hat einen bitweisen Exklusiv-ODER-Operator, es ist ^:

>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False

Sie können es verwenden, indem Sie die Eingaben in Boolesche Werte konvertieren, bevor Sie xor (^) anwenden:

bool(a) ^ bool(b)

(Bearbeitet - danke Arel)

3
Tomer Gal

XOR ist in operator.xor implementiert.

3
lbolla

So rufen Sie das logische xor von zwei oder mehr Variablen in Python ab:

  1. Konvertiert Eingaben in Boolesche Werte
  2. Verwenden Sie den bitweisen Operator xor (^ oder operator.xor)

Zum Beispiel,

bool(a) ^ bool(b)

Wenn Sie die Eingaben in Boolesche Werte konvertieren, wird bitweise xoder logisch xoder.

Beachten Sie, dass die akzeptierte Antwort falsch ist:!= ist nicht dasselbe wie xor in Python, da die Operatorverkettung subtil ist .

Beispielsweise ist das xor der drei folgenden Werte falsch, wenn != verwendet wird:

True ^  False ^  False  # True, as expected of XOR
True != False != False  # False! Equivalent to `(True != False) and (False != False)`

(PS: Ich habe versucht, die akzeptierte Antwort so zu bearbeiten, dass sie diese Warnung enthält, aber meine Änderung wurde abgelehnt.)

2
Arel