在 Python 中如何获取两个变量的逻辑异或?
- 2025-01-08 08:50:00
- admin 原创
- 121
问题描述:
在 Python 中如何获取两个变量的逻辑异或?
例如,我有两个变量,我希望它们是字符串。我想测试其中只有一个包含 True 值(不是 None 或空字符串):
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'
解决方案 1:
如果您已将输入标准化为布尔值,则 != 就是异或。
bool(a) != bool(b)
解决方案 2:
您始终可以使用 xor 的定义从其他逻辑运算中计算它:
(a and not b) or (not a and b)
但这对我来说有点太冗长了,乍一看不是特别清楚。另一种方法是:
bool(a) ^ bool(b)
两个布尔值上的异或运算符是逻辑异或(与 int 不同,后者是按位异或)。这是有道理的,因为bool
只是 的一个子类int
,但实现为仅具有值0
和。当域限制为和 时1
,逻辑异或等同于按位异或。0
`1`
因此该logical_xor
函数的实现如下:
def logical_xor(str1, str2):
return bool(str1) ^ bool(str2)
感谢Python-3000 邮件列表的 Nick Coghlan。
解决方案 3:
按位排他或已经内置到 Python 中,在operator
模块中(与运算符相同^
):
from operator import xor
xor(bool(a), bool(b)) # Note: converting to bools is essential
重要提示
“请注意,这也是按位操作的:xor(1, 2) 返回 3。从文档字符串中可以看出:xor(a, b) - 与 a ^ b 相同。请记住,从运算符导入的任何内容都只是现有内置中缀运算符的功能形式。– askewchan 2013 年 9 月 15 日 16:59”
解决方案 4:
正如Zach所解释的,您可以使用:
xor = bool(a) ^ bool(b)
就我个人而言,我更喜欢稍微不同的方言:
xor = bool(a) + bool(b) == 1
≥1
这种方言的灵感来自于我在学校学到的一种逻辑图表语言,其中“OR”用一个包含(大于或等于 1)的框表示,“XOR”用一个包含 的框表示=1
。
这样做的好处是能够正确实现多个操作数的排他或运算。
“1 = a^b^c...” 表示真操作数的个数为奇数。此运算符为“奇偶校验”。
“1 = a + b + c...” 表示只有一个操作数为真。这是“排他或”,意思是“一个排除其他”。
解决方案 5:
Python 逻辑
or
::如果是则A or B
返回,否则返回A
`bool(A)True
B`Python 逻辑
and
::如果是则A and B
返回,否则返回A
`bool(A)False
B`
为了保留大部分这种思维方式,我的逻辑异或定义是:
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'
解决方案 6:
我测试了几种方法(包括使用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
解决方案 7:
Python 有一个按位排他或运算符,它是^
:
>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False
您可以在应用 xor() 之前将输入转换为布尔值来使用它^
:
bool(a) ^ bool(b)
(已编辑 - 感谢 Arel)
解决方案 8:
简单、易于理解:
sum(bool(a), bool(b)) == 1
如果您想要的是独占选择,即1
从中选择n
,则可以将其扩展为多个参数:
sum(bool(x) for x in y) == 1
解决方案 9:
要在 Python 中获取两个或多个变量的逻辑异或:
将输入转换为布尔值
使用按位异或运算符(
^
或operator.xor
)
例如,
bool(a) ^ bool(b)
当将输入转换为布尔值时,按位异或变为逻辑异或。
请注意,接受的答案是错误的:由于 运算符链!=
的微妙性,与 Python 中的 xor 不同。
例如,使用 时,下面三个值的异或运算是错误的!=
:
True ^ False ^ False # True, as expected of XOR
True != False != False # False! Equivalent to `(True != False) and (False != False)`
(PS:我尝试编辑已接受的答案以包含此警告,但我的更改被拒绝了。)
解决方案 10:
假设 A 和 B 是布尔值。
A is not B
解决方案 11:
由于我没有看到使用变量参数和仅对真值 True 或 False 进行操作的 xor 简单变体,因此我将其放在这里供大家使用。正如其他人所说,它非常(更不用说非常)简单。
def xor(*vars):
result = False
for v in vars:
result = result ^ bool(v)
return result
使用方法也很简单:
if xor(False, False, True, False):
print "Hello World!"
由于这是广义的 n 元逻辑 XOR,因此只要 True 操作数的数量为奇数,它的真值就为 True(并且不仅当恰好有一个为 True 时,这只是 n 元 XOR 为 True 的一种情况)。
因此,如果您要搜索一个仅当其操作数之一为 True 时才为 True 的 n 元谓词,则您可能需要使用:
def isOne(*vars):
result = False
for v in vars:
if result and v:
return False
else:
result = result or v
return result
解决方案 12:
您使用与 C 语言中相同的 XOR 运算符,即^
。
我不知道为什么,但最受欢迎的解决方案建议bool(A) != bool(B)
,而我想说 - 符合 C 的^
运算符,最明显的解决方案是:
bool(A) ^ bool(B)
C
对于来自或衍生语言的人来说,它更具可读性并且可以立即理解C
......
在玩代码高尔夫的时候,可能
not A ^ (not B)
将是赢家。使用not
作为布尔值的转换器(比少一个字母bool()
。并且对于第一个表达式,在某些情况下可以省略括号。嗯,这取决于在必须做的情况下not(A) ^ (not(B))
,bool()
需要相同数量的字母......
解决方案 13:
悬赏帖:
另一个想法...你只需尝试(可能是)pythonic表达式«is not»,以获得逻辑«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
>>>
但是,正如他们上面指出的那样,这取决于您想要提取的任何一对字符串的实际行为,因为字符串不是布尔值……甚至更多:如果您《深入 Python》,您会发现《“and”和“or”的特殊性质》
http://www.diveintopython.net/power_of_introspection/and_or.html
抱歉,我的书面英语不是我的母语。
问候。
解决方案 14:
包括我自己在内的许多人都需要一个xor
像 n 输入异或电路一样运行的函数,其中 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)
示例 I/O 如下:
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
解决方案 15:
我知道这已经很晚了,但我有一个想法,也许值得,只是为了记录。也许这会起作用:np.abs(x-y)
这个想法是
如果 x=True=1 且 y=False=0,则结果将是 |1-0|=1=True
如果 x=False=0 且 y=False=0 那么结果将是 |0-0|=0=False
如果 x=True=1 且 y=True=1,则结果将是 |1-1|=0=False
如果 x=False=0 且 y=True=1,则结果将是 |0-1|=1=True
解决方案 16:
排他或定义如下
def xor( a, b ):
return (a or b) and not (a and b)
解决方案 17:
这里建议的一些实现在某些情况下会导致操作数的重复评估,这可能会导致意想不到的副作用,因此必须避免。
也就是说,xor
返回True
或 的实现False
相当简单;如果可能的话,返回其中一个操作数的实现则要复杂得多,因为对于应该选择哪个操作数没有共识,尤其是当有两个以上的操作数时。例如,应该xor(None, -1, [], True)
返回None
,[]
还是False
?我敢打赌,对于某些人来说,每个答案看起来都是最直观的。
对于 True 或 False 结果,有多达五种可能的选择:返回第一个操作数(如果它与最终结果的值匹配,否则为布尔值)、返回第一个匹配项(如果至少存在一个,否则为布尔值)、返回最后一个操作数(如果 ... 否则 ...)、返回最后一个匹配项(如果 ... 否则 ...),或者始终返回布尔值。总共有 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) t: %d (%s) x: %s' % (f, choices[f], t, choices[t], x))
print()
解决方案 18:
有时我发现自己使用 1 和 0 而不是布尔 True 和 False 值。在这种情况下,xor 可以定义为
z = (x + y) % 2
其真值表如下:
x
|0|1|
-+-+-+
0|0|1|
y -+-+-+
1|1|0|
-+-+-+
解决方案 19:
这个怎么样?
(not b and a) or (not a and b)
a
如果b
为假则给予如果为假则
给予否则
给予b
`a` False
或者使用 Python 2.5+ 三元表达式:
(False if a else b) if b else a
解决方案 20:
Xor 是^
Python 中的函数。它返回:
对整数进行按位异或
布尔值的逻辑异或
集合的专属联合
实现的类的用户定义结果
__xor__
。对于未定义类型(例如字符串或字典)会出现 TypeError。
如果您无论如何都打算在字符串上使用它们,则将它们强制转换bool
会使您的操作变得明确(您也可以意味着set(str1) ^ set(str2)
)。
解决方案 21:
这就是我编写真值表的方法。具体来说,对于异或,我们有:
| a | b | xor | |
|---|----|-------|-------------|
| T | T | F | |
| T | F | T | a and not b |
| F | T | T | not a and b |
| F | F | F | |
只需查看答案栏中的 T 值,并将所有真实情况用逻辑或连接在一起。因此,此真值表可能在情况 2 或 3 中生成。因此,
xor = lambda a, b: (a and not b) or (not a and b)
解决方案 22:
排他或(XOR)的含义可能令人困惑,但可能会引导您到这里。
这是一个排他性检查,其功能类似于两个变量的传统 XOR ,但对于多个变量,其操作类似于One-Hot 。
我所看到的相对于其他实现的唯一好处是它短路并且不那么神奇。
def exclusive(*opts):
count = 0
for value in opts:
if bool(value): # If truthy
count += 1
if count > 1: # Short-circuit
return False
return count == 1 # Only Return True if one truthy found
下面是 XOR 和 ONE-HOT 之间差异的表格作为示例:
a|b|c|d --- xor|one-hot
-----------------------
0|0|0|0 --> 0 |0
0|0|0|1 --> 1 |1
0|0|1|0 --> 1 |1
0|0|1|1 --> 0 |0
0|1|0|0 --> 1 |1
0|1|0|1 --> 0 |0
0|1|1|0 --> 0 |0
0|1|1|1 --> 1 |0 # noted difference
1|0|0|0 --> 1 |1
1|0|0|1 --> 0 |0
1|0|1|0 --> 0 |0
1|0|1|1 --> 1 |0 # noted difference
1|1|0|0 --> 0 |0
1|1|0|1 --> 1 |0 # noted difference
1|1|1|0 --> 1 |0 # noted difference
1|1|1|1 --> 0 |0
解决方案 23:
如果你知道 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)))
解决方案 24:
这是 map-reduce 泛化的实现。请注意,这相当于functools.reduce(lambda x, y: x != y, map(bool, orands))
。
def xor(*orands):
return bool(sum(bool(x) for x in orands) % 2)
如果您正在寻找独热检测器,这里有一个概括。这个概括可能符合英语中“排他或”的用法(例如“一美元可以买一杯果汁、咖啡或茶”),但它不符合典型的操作顺序。例如xor_1hot(1,1,1) == 0 != 1 == xor_1hot(xor_1hot(1,1),1)
。
def xor_1hot(*orands):
return sum(bool(x) for x in orands) == 1
您可以使用以下方式进行测试
# test
from itertools import product
n = 3
total_true = 0
for inputs in product((False, True), repeat=n):
y = xor(*inputs)
total_true += int(y)
print(f"{''.join(str(int(b)) for b in inputs)}|{y}")
print('Total True:', total_true)
独热检测器输出:
000|假
001|正确
010|正确
011|错误
100|正确
101|错误
110|错误
111|错误
正确总数:3
Map-Reduce 输出:
000|假
001|真
010|真
011|假
100|真
101|假
110|假
111|真
总计真数:4
解决方案 25:
只是因为我没有在其他地方看到过它,但这也能起到作用:
def logical_xor(a, b):
return not b if a else bool(b)
我不确定它是否比公认的解决方案 bool(a) != bool(b)“更好”/更易读/更符合 Python 风格。
解决方案 26:
XOR 在 中实现operator.xor
。
解决方案 27:
xor = ((False, True), (True, False)
eq = (xor[1], xor[0])
xor[False][True] # yields True
优点:
明确的
使逻辑门操作可用
可以将其定义为(False,True)、(0,1)等
如果需要,可以使用列表而不是元组
。
缺点:
非标准
主观上愚蠢
可能比其他方法性能更差
解决方案 28:
Python 处理逻辑运算的方式可能令人困惑,因此我的实现为用户提供了简单的 True/False 答案选项(默认情况下)。可以通过将可选的第三个参数设置为 None 来获取实际的 Python 结果。
def xor(a, b, true=True, false=False): # set true to None to get actual Python result
ab1 = a and not b
ab2 = not a and b
if bool(ab1) != bool(ab2):
return (ab1 or ab2) if true is None else true
else:
return false
解决方案 29:
我们可以使用以下方法轻松找到两个变量的异或:
def xor(a,b):
return a !=b
例子:
xor(True,False) >>> True