Einige der hier vorgeschlagenen Implementierungen führen in manchen Fällen zu einer wiederholten Auswertung der Operanden, was zu unbeabsichtigten Nebeneffekten führen kann und daher vermieden werden muss.
Das heißt, ein xor
Implementierung, die entweder True
o False
ist relativ einfach; eine, die einen der Operanden zurückgibt, wenn dies möglich ist, ist viel schwieriger, weil kein Konsens darüber besteht, welcher Operand der gewählte sein soll, insbesondere wenn es mehr als zwei Operanden gibt. Zum Beispiel, sollte xor(None, -1, [], True)
return None
, []
o False
? Ich wette, jede Antwort erscheint manchen Menschen als die intuitivste.
Für das Wahr- oder Falsch-Ergebnis gibt es bis zu fünf Möglichkeiten: erster Operand zurückgeben (wenn er mit dem Endergebnis im Wert übereinstimmt, sonst boolesch), erste Übereinstimmung zurückgeben (wenn mindestens eine vorhanden ist, sonst boolesch), letzter Operand zurückgeben (wenn ... sonst ...), letzte Übereinstimmung zurückgeben (wenn ... sonst ...), oder immer boolesch zurückgeben. Insgesamt sind das 5 ** 2 = 25 Varianten 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 Stimmen
Wie definiert man "xor" für ein Paar von Zeichenketten? Was sollte "abc" ^ "" Ihrer Meinung nach zurückgeben, was es nicht tut?
25 Stimmen
Es sollte True zurückgeben, anstatt eine Exception auszulösen, da nur eine der Zeichenketten True ist, wie durch den normalen Python-Typ bool definiert.
72 Stimmen
Ich bin erstaunt, dass Python keinen Infix-Operator namens "xor" hat, was die intuitivste, pythonische Implementierung wäre. Die Verwendung von "^" ist konsistent mit anderen Sprachen, aber nicht so offensichtlich lesbar wie das meiste in Python.
23 Stimmen
@MehrdadAfshari Die offensichtliche Antwort auf Ihre Frage ist, dass
a xor a
ist definiert als(a and not b) or (not a and b)
, und soa xor b
wenna
etb
Zeichenketten oder andere Typen sind, sollten das ergeben, was(a and not b) or (not a and b)
erbringt.2 Stimmen
Das Problem ist, dass die Dokumentation unzureichend ist. ^ ist "bitweises exklusives oder", was wörtlich interpretiert Bit für Bit bedeutet, nicht bool für bool. x'FFFF00' ^ x'FFFF00' sollte also x'000000' sein. Oder soll dies nur auf der Basis von einzelnen Zeichen geschehen, die als Zahlen gegossen werden? Wir müssen die kürzeren Zeichen der Zeichenkette iterieren, um sie an die Länge der längeren Zeichenkette anzupassen. All dies sollte eingebaut sein.
0 Stimmen
@mckenzm Falls Ihnen das weiterhilft,
int("0xFFFF00", 16) ^ int("0xFFFF00", 16) == int(0)
also ja, Sie müssen die Nummer eingeben und anrufenhex
auf das Ergebnis und füllt dann das Ergebnis mit genügend 0 auf der linken Seite auf, um die längste Länge zu erreichen.0 Stimmen
@Guimoute Danke, das ist ein bisschen Arbeit, aber mit Füllung/Ausrichtung machbar.