简体   繁体   English

你如何在 Python 中获得两个变量的逻辑异或?

[英]How do you get the logical xor of two variables in Python?

How do you get the logical xor of two variables in Python?你如何在 Python 中获得两个变量的逻辑异或?

For example, I have two variables that I expect to be strings.例如,我有两个希望是字符串的变量。 I want to test that only one of them contains a True value (is not None or the empty string):我想测试其中只有一个包含 True 值(不是 None 或空字符串):

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

The ^ operator seems to be bitwise, and not defined on all objects: ^运算符似乎是按位的,并没有在所有对象上定义:

>>> 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'

如果您已经将输入规范化为布尔值,则 != 是异或。

bool(a) != bool(b)

You can always use the definition of xor to compute it from other logical operations:您始终可以使用 xor 的定义从其他逻辑运算中计算它:

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

But this is a little too verbose for me, and isn't particularly clear at first glance.但这对我来说有点太冗长了,乍一看并不是特别清楚。 Another way to do it is:另一种方法是:

bool(a) ^ bool(b)

The xor operator on two booleans is logical xor (unlike on ints, where it's bitwise).两个布尔值的异或运算符是逻辑异或(与整数不同,它是按位的)。 Which makes sense, since bool is just a subclass of int , but is implemented to only have the values 0 and 1 .这是有道理的,因为bool只是int的子类,但被实现为只有值01 And logical xor is equivalent to bitwise xor when the domain is restricted to 0 and 1 .当域被限制为01时,逻辑异或等效于按位异或。

So the logical_xor function would be implemented like:所以logical_xor函数将实现如下:

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

Credit to Nick Coghlan on the Python-3000 mailing list . 归功于 Python-3000 邮件列表中的 Nick Coghlan

Bitwise exclusive-or is already built-in to Python, in theoperator module (which is identical to the ^ operator):按位异或已经内置于 Python 中,位于operator模块中(与^运算符相同):

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

As Zach explained, you can use:正如Zach解释的那样,您可以使用:

xor = bool(a) ^ bool(b)

Personally, I favor a slightly different dialect:就个人而言,我喜欢稍微不同的方言:

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

This dialect is inspired from a logical diagramming language I learned in school where "OR" was denoted by a box containing ≥1 (greater than or equal to 1) and "XOR" was denoted by a box containing =1 .这种方言的灵感来自我在学校学到的逻辑图表语言,其中“OR”由包含≥1 (大于或等于1)的框表示,“XOR”由包含=1的框表示。

This has the advantage of correctly implementing exclusive or on multiple operands.这具有正确实现异或多个操作数的优点。

  • "1 = a ^ b ^ c..." means the number of true operands is odd. “1 = a ^ b ^ c...”表示真实操作数的数量是奇数。 This operator is "parity".这个运算符是“奇偶校验”。
  • "1 = a + b + c..." means exactly one operand is true. “1 = a + b + c...”表示恰好有一个操作数为真。 This is "exclusive or", meaning "one to the exclusion of the others".这是“独占或”,意思是“一个排除其他”。
  • Python logical or : A or B : returns A if bool(A) is True , otherwise returns B蟒逻辑orA or B :返回A如果bool(A)True ,否则返回B
  • Python logical and : A and B : returns A if bool(A) is False , otherwise returns B蟒逻辑andA and B :返回A如果bool(A)False ,否则返回B

To keep most of that way of thinking, my logical xor definintion would be:为了保持这种思维方式,我的逻辑异或定义是:

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

That way it can return a , b , or False :这样它就可以返回abFalse

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

I've tested several approaches and not a != (not b) appeared to be the fastest.我已经测试了几种方法,而not a != (not b)似乎是最快的。

Here are some tests这里有一些测试

%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: Examples 1 and 3 above are missing parenthes so result is incorrect.编辑:上面的示例 1 和 3 缺少括号,因此结果不正确。 New results + truth() function as ShadowRanger suggested. ShadowRanger 建议的新结果 + truth()函数。

%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

Python has a bitwise exclusive-OR operator, it's ^ : Python 有一个按位异或运算符,它是^

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

You can use it by converting the inputs to booleans before applying xor ( ^ ):您可以通过在应用 xor ( ^ ) 之前将输入转换为布尔值来使用它:

bool(a) ^ bool(b)

(Edited - thanks Arel) (已编辑 - 感谢 Arel)

Simple, easy to understand:简单易懂:

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

If an exclusive choice is what you're after, ie to select 1 choice out of n , it can be expanded to multiple arguments:如果您追求的是排他选择,即从n选择1选项,则可以将其扩展为多个参数:

sum(bool(x) for x in y) == 1

As I don't see the simple variant of xor using variable arguments and only operation on Truth values True or False, I'll just throw it here for anyone to use.由于我没有看到使用可变参数的 xor 的简单变体,并且只对真值 True 或 False 进行操作,因此我将把它放在这里供任何人使用。 It's as noted by others, pretty (not to say very) straightforward.正如其他人所指出的那样,非常(不是说非常)直截了当。

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

And usage is straightforward as well:用法也很简单:

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

As this is the generalized n-ary logical XOR, it's truth value will be True whenever the number of True operands is odd (and not only when exactly one is True, this is just one case in which n-ary XOR is True).由于这是广义的 n-ary 逻辑 XOR,当 True 操作数的数量为奇数时,它的真值将为 True(不仅当恰好有一个为 True 时,这只是 n-ary XOR 为 True 的一种情况)。

Thus if you are in search of a n-ary predicate that is only True when exactly one of it's operands is, you might want to use:因此,如果您正在寻找一个 n 元谓词,该谓词仅在其操作数中的一个为 True 时为真,您可能需要使用:

def isOne(*vars):
    result = False
    for v in vars:
        if result and v:
            return False
        else:
            result = result or v
    return result

Rewarding thread:奖励线程:

Anoder idea... Just you try the (may be) pythonic expression «is not» in order to get behavior of logical «xor»阳极的想法......只是你尝试(可能是)pythonic表达式“不是”以获得逻辑“xor”的行为

The truth table would be:真值表将是:

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

And for your example string:对于您的示例字符串:

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

However;然而; as they indicated above, it depends of the actual behavior you want to pull out about any couple strings, because strings aren't boleans... and even more: if you «Dive Into Python» you will find «The Peculiar Nature of "and" and "or"» http://www.diveintopython.net/power_of_introspection/and_or.html正如他们上面指出的,这取决于你想要提取的关于任何一对字符串的实际行为,因为字符串不是 boleans ......甚至更多:如果你 «Dive Into Python» 你会发现 «The Peculiar Nature of“和”和“或”» http://www.diveintopython.net/power_of_introspection/and_or.html

Sorry my writed English, it's not my born language.对不起,我写的英语不是我天生的语言。

Regards.问候。

I know this is late, but I had a thought and it might be worth, just for documentation.我知道这已经晚了,但我有一个想法,它可能是值得的,只是为了文档。 Perhaps this would work: np.abs(xy) The idea is that也许这会奏效: np.abs(xy)这个想法是

  1. if x=True=1 and y=False=0 then the result would be |1-0|=1=True如果 x=True=1 和 y=False=0 那么结果将是 |1-0|=1=True
  2. if x=False=0 and y=False=0 then the result would be |0-0|=0=False如果 x=False=0 和 y=False=0 那么结果将是 |0-0|=0=False
  3. if x=True=1 and y=True=1 then the result would be |1-1|=0=False如果 x=True=1 和 y=True=1 那么结果将是 |1-1|=0=False
  4. if x=False=0 and y=True=1 then the result would be |0-1|=1=True如果 x=False=0 和 y=True=1 那么结果将是 |0-1|=1=True

To get the logical xor of two or more variables in Python:要在 Python 中获取两个或多个变量的逻辑异或:

  1. Convert inputs to booleans将输入转换为布尔值
  2. Use the bitwise xor operator ( ^ or operator.xor )使用按位异或operator.xor符( ^operator.xor

For example,例如,

bool(a) ^ bool(b)

When you convert the inputs to booleans, bitwise xor becomes logical xor.当您将输入转换为布尔值时,按位异或变为逻辑异或。

Note that the accepted answer is wrong: != is not the same as xor in Python because of the subtlety of operator chaining .请注意,接受的答案是错误的: !=与 Python 中的 xor 不同,因为operator chaining的微妙之处。

For instance, the xor of the three values below is wrong when using != :例如,使用!=时,以下三个值的异或是错误的:

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

(PS I tried editing the accepted answer to include this warning, but my change was rejected.) (PS 我尝试编辑接受的答案以包含此警告,但我的更改被拒绝。)

You use the same XOR operator like in C, which is ^ .您使用与 C 中相同的 XOR 运算符,即^

I don't know why, but the most upvoted solution suggests bool(A) != bool(B) , while I would say - in conformity with C's ^ 's operator, the most obvious solution is:我不知道为什么,但最受支持的解决方案建议bool(A) != bool(B) ,而我会说 - 根据 C 的^运算符,最明显的解决方案是:

bool(A) ^ bool(B)

which is more readable and immediately understandable for anyone coming from C or any C -derived language...对于来自C或任何C派生语言的任何人来说,它更具可读性和立即理解......

when doing code-golfing, probably在打代码时,可能

not A ^ (not B)

will be the winner.将是赢家。 with not as converter for boolean (one letter less than bool() . And for the first expression in some cases one can leave out the parantheses. Well, it depends, in cases where one has to do not(A) ^ (not(B)) , the bool() needs same amount of letters... with not as converter for boolean (one letter less than bool() 。在某些情况下,对于第一个表达式,可以省略括号。好吧,这取决于,在必须做的情况下not(A) ^ (not(B))bool()需要相同数量的字母......

Sometimes I find myself working with 1 and 0 instead of boolean True and False values.有时我发现自己使用 1 和 0 而不是布尔 True 和 False 值。 In this case xor can be defined as在这种情况下,xor 可以定义为

z = (x + y) % 2

which has the following truth table:它具有以下真值表:

     x
   |0|1|
  -+-+-+
  0|0|1|
y -+-+-+
  1|1|0|
  -+-+-+

Exclusive Or is defined as follows异或定义如下

def xor( a, b ):
    return (a or b) and not (a and b)

Some of the implementations suggested here will cause repeated evaluation of the operands in some cases, which may lead to unintended side effects and therefore must be avoided.这里建议的一些实现在某些情况下会导致对操作数的重复评估,这可能会导致意想不到的副作用,因此必须避免。

That said, a xor implementation that returns either True or False is fairly simple;也就是说,返回TrueFalsexor实现相当简单; one that returns one of the operands, if possible, is much trickier, because no consensus exists as to which operand should be the chosen one, especially when there are more than two operands.如果可能,返回其中一个操作数的方法要复杂得多,因为对于应选择哪个操作数没有达成共识,尤其是在有两个以上的操作数时。 For instance, should xor(None, -1, [], True) return None , [] or False ?例如, xor(None, -1, [], True)返回None[]还是False I bet each answer appears to some people as the most intuitive one.我敢打赌,每个答案在某些人看来都是最直观的。

For either the True- or the False-result, there are as many as five possible choices: return first operand (if it matches end result in value, else boolean), return first match (if at least one exists, else boolean), return last operand (if ... else ...), return last match (if ... else ...), or always return boolean.对于 True- 或 False-结果,有多达五种可能的选择:返回第一个操作数(如果它与值中的最终结果匹配,否则为布尔值),返回第一个匹配项(如果至少存在一个,则为布尔值),返回最后一个操作数(if ... else ...),返回最后一个匹配(if ... else ...),或者总是返回布尔值。 Altogether, that's 5 ** 2 = 25 flavors of xor .总共有 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()

How about this?这个怎么样?

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

will give a if b is false如果b为假,将给出a
will give b if a is false如果a为假,将给出b
will give False otherwise否则会给出False

Or with the Python 2.5+ ternary expression:或者使用 Python 2.5+ 三元表达式:

(False if a else b) if b else a

Many folks, including myself, need an xor function that behaves like an n-input xor circuit, where n is variable.许多人,包括我自己,都需要一个xor函数,它的行为类似于 n 输入 xor 电路,其中 n 是可变的。 (See https://en.wikipedia.org/wiki/XOR_gate ). (参见https://en.wikipedia.org/wiki/XOR_gate )。 The following simple function implements this.下面的简单函数实现了这一点。

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)

Sample I/O follows:示例 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

Xor is ^ in Python. Xor 在 Python 中是^ It returns :它返回:

  • A bitwise xor for ints整数的按位异或
  • Logical xor for bools bool 的逻辑异或
  • An exclusive union for sets集合的唯一并集
  • User-defined results for classes that implements __xor__ .实现__xor__类的用户定义结果。
  • TypeError for undefined types, such as strings or dictionaries.未定义类型的 TypeError,例如字符串或字典。

If you intend to use them on strings anyway, casting them in bool makes your operation unambiguous (you could also mean set(str1) ^ set(str2) ).如果您打算在字符串上使用它们,将它们转换为bool会使您的操作明确(您也可以指set(str1) ^ set(str2) )。

This gets the logical exclusive XOR for two (or more) variables这将获得两个(或更多)变量的逻辑异或异或

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

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

The first problem with this setup is that it most likely traverses the whole list twice and, at a minimum, will check at least one of the elements twice.这种设置的第一个问题是它很可能会遍历整个列表两次,并且至少会检查至少一个元素两次。 So it may increase code comprehension, but it doesn't lend to speed (which may differ negligibly depending on your use case).因此,它可能会提高代码理解能力,但不会提高速度(根据您的用例,速度可能会略有不同)。

The second problem with this setup is that it checks for exclusivity regardless of the number of variables.这种设置的第二个问题是它检查排他性而不管变量的数量。 This is may at first be regarded as a feature, but the first problem becomes a lot more significant as the number of variables increases (if they ever do).这最初可能被视为一个特征,但随着变量数量的增加(如果它们曾经这样做的话),第一个问题变得更加重要。

It's easy when you know what XOR does:当您知道 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))

This is how I would code up any truth table.这就是我编写任何真值表的方式。 For xor in particular we have:特别是对于异或,我们有:

| a | b  | xor   |             |
|---|----|-------|-------------|
| T | T  | F     |             |
| T | F  | T     | a and not b |
| F | T  | T     | not a and b |
| F | F  | F     |             |

Just look at the T values in the answer column and string together all true cases with logical or.只需查看答案列中的 T 值,并用逻辑或将所有真实情况串在一起。 So, this truth table may be produced in case 2 or 3. Hence,所以,这个真值表可能在情况 2 或 3 中产生。因此,

xor = lambda a, b: (a and not b) or (not a and b)

XOR 在operator.xor实现。

鉴于 A 和 B 是布尔值。

A is not B

Just because I haven't seen it mentioned elsewhere, this also does the trick:只是因为我没有在其他地方看到它,所以这也可以解决问题:

def logical_xor(a, b):
    return not b if a else bool(b)

I'm not sure if it's "better"/more readable/more pythonic than the accepted solution bool(a).= bool(b).我不确定它是否比公认的解决方案 bool(a).= bool(b)“更好”/更具可读性/更 pythonic。

Here's an implementation of the map-reduce generalization.这是 map-reduce 泛化的实现。 Note that this is equivalent to functools.reduce(lambda x, y: x,= y, map(bool, orands)) .请注意,这等效于functools.reduce(lambda x, y: x,= y, map(bool, orands))

def xor(*orands):
    return bool(sum(bool(x) for x in orands)) % 2

Here's a generalization if you're looking for a one-hot detector.如果您正在寻找单热检测器,这是一个概括。 This generalization may fit the English language use of exclusive-or, (eg "For a dollar you can buy a juice or coffee or tea"), but it doesn't match the typical order of operations.这种概括可能符合排他或的英语用法(例如“花一美元你可以买果汁或咖啡或茶”),但它不符合典型的操作顺序。 Eg xor_1hot(1,1,1) == 0,= 1 == xor_1hot(xor_1hot(1,1),1) .例如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

You can test either with您可以使用

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

One-Hot Detector Output:单热检测器输出:

000|False 000|错误
001|True 001|真
010|True 010|真
011|False 011|错误
100|True 100|真
101|False 101|错误
110|False 110|错误
111|False 111|错误
Total True: 3真实总数:3

Map-Reduce Output: Map-Reduce 输出:

000|False 000|错误
001|True 001|真
010|True 010|真
011|False 011|错误
100|True 100|真
101|False 101|错误
110|False 110|错误
111|True 111|真
Total True: 4真实总数:4

The way that Python handles logic operations can be confusing, so my implementation gives the user the option (by default) of a simple True/False answer. Python 处理逻辑操作的方式可能令人困惑,因此我的实现为用户提供了一个简单的 True/False 答案选项(默认情况下)。 The actual Python result can be obtained by setting the optional third arg to None.可以通过将可选的第三个 arg 设置为 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

How do you get the logical xor of two variables in Python?如何在Python中获得两个变量的逻辑异或?

For example, I have two variables that I expect to be strings.例如,我有两个期望是字符串的变量。 I want to test that only one of them contains a True value (is not None or the empty string):我想测试其中只有一个包含True值(不是None或空字符串):

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

The ^ operator seems to be bitwise, and not defined on all objects: ^运算符似乎是按位的,并且未在所有对象上都定义:

>>> 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'

We can easily find xor of two variables by the using:我们可以使用以下方法轻松找到两个变量的异或:

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

Example:例子:

xor(True,False) >>> True xor(True,False) >>> 真

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM