Ответ 1
Если вы уже нормализуете входы для булевых, то!= is xor.
bool(a) != bool(b)
Как вы получаете логический xor двух переменных в Python?
Например, у меня есть две переменные, которые я ожидаю быть строками. Я хочу проверить, что только один из них содержит значение True (не является ничем или пустой строкой):
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
if logical_xor(str1, str2):
print "ok"
else:
print "bad"
Оператор ^
кажется побитовым и не определен для всех объектов:
>>> 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'
Если вы уже нормализуете входы для булевых, то!= is xor.
bool(a) != bool(b)
Вы всегда можете использовать определение xor для вычисления его из других логических операций:
(a and not b) or (not a and b)
Но это немного слишком много для меня, и на первый взгляд это не особенно понятно. Другой способ сделать это:
bool(a) ^ bool(b)
Оператор xor на двух логических операциях является логическим xor (в отличие от ints, где он побитовым). Это имеет смысл, так как bool
является всего лишь подклассом int
, но реализуется только для значений 0
и 1
. И логический xor эквивалентен побитовому xor, когда домен ограничен 0
и 1
.
Таким образом, функция logical_xor
будет реализована так:
def logical_xor(str1, str2):
return bool(str1) ^ bool(str2)
Побитовое исключение или уже встроено в Python в модуле operator
(что идентично оператору ^
):
from operator import xor
xor(bool(a), bool(b)) # Note: converting to bools is essential
Как объясняется Зак, вы можете использовать:
xor = bool(a) ^ bool(b)
Лично я предпочитаю немного другой диалект:
xor = bool(a) + bool(b) == 1
Этот диалект вдохновлен логическим языком диаграмм, который я изучил в школе, где "OR" обозначался ящиком, содержащим ≥1
(больше или равным 1), а "XOR" обозначался ящиком, содержащим =1
.
Это имеет то преимущество, что он правильно реализует эксклюзив или несколько операндов.
or
: A or B
: возвращает A
, если bool(A)
is True
, в противном случае возвращает B
and
: A and B
: возвращает A
, если bool(A)
is False
, в противном случае возвращает B
Чтобы сохранить большую часть этого образа мышления, моя логическая xor-проверка была бы следующей:
def logical_xor(a, b):
if bool(a) == bool(b):
return False
else:
return a or b
Таким образом, он может вернуть A
, B
или False
:
>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'
Я протестировал несколько подходов, и not a != (not b)
оказался самым быстрым.
Вот несколько тестов
%timeit not a != (not b)
10000000 loops, best of 3: 78.5 ns per loop
%timeit bool(a) != bool(b)
1000000 loops, best of 3: 343 ns per loop
%timeit not a ^ (not b)
10000000 loops, best of 3: 131 ns per loop
Edit:
В примерах 1 и 3 выше отсутствуют круглые скобки, поэтому результат неверен. Новые результаты + функция truth()
, как предложил ShadowRanger.
%timeit (not a) ^ (not b) # 47 ns
%timeit (not a) != (not b) # 44.7 ns
%timeit truth(a) != truth(b) # 116 ns
%timeit bool(a) != bool(b) # 190 ns
Награждение темы:
Идея анодера... Просто попробуйте (может быть) питонское выражение "нет", чтобы получить логическое поведение "xor"
Таблица истинности будет:
>>> True is not True
False
>>> True is not False
True
>>> False is not True
True
>>> False is not False
False
>>>
И для вашего примера строка:
>>> "abc" is not ""
True
>>> 'abc' is not 'abc'
False
>>> 'abc' is not ''
True
>>> '' is not 'abc'
True
>>> '' is not ''
False
>>>
Тем не мение; как они указывали выше, это зависит от фактического поведения, которое вы хотите извлечь из любой пары строк, потому что строки не являются логическими значениями... и даже более того: если вы "Dive Into Python", вы найдете "Особую природу" и "и" или "" http://www.diveintopython.net/power_of_introspection/and_or.html
Извините мой английский, это не мой родной язык.
С уважением.
Эксклюзивный или определяется следующим образом
def xor( a, b ):
return (a or b) and not (a and b)
Поскольку я не вижу простого варианта xor, использующего переменные аргументы и только операции со значениями True, True или False, я просто брошу его здесь для любого использования. Это, как отмечают другие, довольно (если не сказать очень) просто.
def xor(*vars):
sum = False
for v in vars:
sum = sum ^ bool(v)
return sum
И использование также просто:
if xor(False, False, True, False):
print "Hello World!"
Так как это обобщенный n-арный логический XOR, его значение истинности будет истинным, когда число операндов True нечетно (и не только, когда точно один равен True, это только один случай, когда n-арный XOR равен True).
Таким образом, если вы ищете n-арный предикат, который имеет значение True только тогда, когда есть только один из его операндов, вы можете использовать:
def isOne(*vars):
sum = False
for v in vars:
if sum and v:
return False
else:
sum = sum or v
return sum
Иногда мне приходится работать с 1 и 0 вместо логических значений True и False. В этом случае xor можно определить как
z = (x + y) % 2
который имеет следующую таблицу истинности:
x
|0|1|
-+-+-+
0|0|1|
y -+-+-+
1|1|0|
-+-+-+
Я знаю, что это поздно, но я подумал, и это может стоить, просто для документации. Возможно, это сработало бы: np.abs(x-y)
Идея в том, что
Просто, легко понять:
sum( (bool(a), bool(b) ) == 1
Если вам нужен эксклюзивный выбор, его можно расширить до нескольких аргументов:
sum( bool(x) for x in y ) % 2 == 1
Как насчет этого?
(not b and a) or (not a and b)
даст a
, если b
false
даст b
, если a
ложно
даст False
иначе
Или с тернарным выражением Python 2.5+:
(False if a else b) if b else a
Некоторые из предложенных здесь реализаций приведут к повторной оценке операндов в некоторых случаях, что может привести к непреднамеренным побочным эффектам, и поэтому их следует избегать.
Тем не менее, реализация xor
, которая возвращает либо True
, либо False
, довольно проста; тот, который возвращает один из операндов, если это возможно, намного сложнее, потому что не существует консенсуса относительно того, какой операнд должен быть выбранным, особенно когда имеется более двух операндов. Например, если xor(None, -1, [], True)
возвращает None
, []
или False
? Бьюсь об заклад, каждый ответ кажется некоторым людям наиболее интуитивным.
Для True или False-результата доступно до пяти возможных вариантов: возвратите первый операнд (если он соответствует конечному результату в значении, else boolean), верните первое совпадение (если хотя бы один существует, иначе boolean), вернуть последний операнд (если... else...), вернуть последнее соответствие (if... else...) или всегда возвращать логическое значение. В целом, это 5 ** 2 = 25 ароматов 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()
Многим людям, включая меня, нужна функция xor
, которая ведет себя как схема с n-входом xor, где n - переменная. (См. https://en.wikipedia.org/wiki/XOR_gate). Следующая простая функция реализует это.
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)
Ниже приведен пример ввода/вывода:
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
Легко, когда вы знаете, что делает 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))
Это получает логический исключительный XOR для двух (или более) переменных
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
any([str1, str2]) and not all([str1, str2])
Первая проблема с этой установкой состоит в том, что она, скорее всего, пересекает весь список дважды и, как минимум, проверит хотя бы один из этих элементов дважды. Таким образом, это может увеличить понимание кода, но оно не дает скорости (что может незначительно отличаться в зависимости от вашего варианта использования).
Вторая проблема с этой установкой заключается в том, что она проверяет исключительность независимо от количества переменных. Сначала это можно рассматривать как функцию, но первая проблема становится намного более значительной, поскольку число переменных увеличивается (если они когда-либо).
Xor это ^
в Python. Возвращает:
__xor__
. Если вы все равно намереваетесь использовать их в строках, приведение их в bool
делает вашу работу однозначной (вы также можете обозначить set(str1) ^ set(str2)
).
В Python есть побитовый оператор исключающего ИЛИ, это ^
:
>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False
Вы можете использовать его, преобразовав входные данные в логические значения перед применением xor (^
):
bool(a) ^ bool(b)
(отредактировано - спасибо, Арель)
Чтобы получить логический xor двух или более переменных в Python:
^
или operator.xor
)Например,
bool(a) ^ bool(b)
Когда вы конвертируете входные данные в логические значения, битовый xor становится логическим xor.
Обратите внимание, что принятый ответ неверен: !=
не совпадает с xor в Python из-за тонкости объединения операторов.
Например, xor из трех значений ниже является неправильным при использовании !=
:
True ^ False ^ False # True, as expected of XOR
True != False != False # False! Equivalent to '(True != False) and (False != False)'
(P.S. я попытался отредактировать принятый ответ, чтобы включить это предупреждение, но мое изменение было отклонено.)
XOR реализуется в operator.xor
.
Мы можем легко найти xor двух переменных, используя:
def xor(a,b):
return a !=b
Пример:
xor (верно, неверно) >>> верно