Pythonで2つの変数の 論理xor をどのように取得しますか?
たとえば、私は文字列であると期待する2つの変数があります。そのうちの1つのみに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'
すでにブール値への入力を正規化しているのであれば、!=はxorです。
bool(a) != bool(b)
Xorの定義を他の論理演算から計算するためにいつでも使用できます。
(a and not b) or (not a and b)
しかし、これは私にとっては少し冗長すぎるため、一見したところ特に明確ではありません。それを行う別の方法は、次のとおりです。
bool(a) ^ bool(b)
2つのブール値のxor演算子は論理xorです(ビット単位のint型とは異なり)。 bool
は単なるint
のサブクラスなので、これは理にかなっていますが、値0
と1
を持つように実装されています。ドメインが0
および1
に制限されている場合、論理xorはビットごとのxorと同等です。
そのため、logical_xor
関数は次のように実装されます。
def logical_xor(str1, str2):
return bool(str1) ^ bool(str2)
Python-3000メーリングリストの Nick Coghlanの功績による 。
operator
モジュールで、排他的論理和はすでにPythonに組み込まれています。
from operator import xor
xor(bool(a), bool(b))
Zach の説明のとおり、次のものを使用できます。
xor = bool(a) ^ bool(b)
個人的には、少し違った方言を好みます。
xor = bool(a) + bool(b) == 1
この方言は、私が学校で学んだ論理的な図表作成言語からヒントを得たもので、「OR」は≥1
(1以上)を含むボックスで、「XOR」は=1
を含むボックスで表されます。
これには、排他的または複数のオペランドに対して正しく実装するという利点があります。
or
:A or B
:bool(A)
がA
であればTrue
を返し、そうでなければB
を返しますand
:A and B
:bool(A)
がA
であれば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
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
やりがいのあるスレッド:
Anoder idea ...論理的なxorの振る舞いを得るために、Pythonic式is is notを試してみてください。
真理値表は次のようになります。
>>> 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
>>>
しかしながら;上に示したように、文字列は真偽値ではないため、実際にどのようなカップルの文字列を引き出すかによって異なります。そして「and」または「» http://www.diveintopython.net/power_of_introspection/and_or.html
私が書いた英語をすみません、それは私の生まれた言語ではありません。
よろしく。
私はこれが遅れていることを知っています、しかし私は考えを持っていました、そしてそれはただ文書化のために、価値があるかもしれません。おそらくこれでうまくいくでしょう:np.abs(x-y)
アイデアは
排他的論理和は次のように定義されます。
def xor( a, b ):
return (a or b) and not (a and b)
変数引数を使用し、真理値TrueまたはFalseに対する操作のみを使用するxorの単純な変形は見られないので、だれでも使用できるようにここでそれをスローします。それは他の人が指摘したように、かなり(言うまでもなく)簡単です。
def xor(*vars):
sum = bool(False)
for v in vars:
sum = sum ^ bool(v)
return sum
使い方も簡単です。
if xor(False, False, True, False):
print "Hello World!"
これは一般化されたn進論理XORなので、Trueオペランドの数が奇数であるときはいつでも真の値がTrueになります(厳密に1つがTrueのときだけでなく、n-ary XORはTrueです。
したがって、そのオペランドの1つだけが真であるときにのみ真となるn-ary述語を探しているなら、あなたは使いたいかもしれません:
def isOne(*vars):
sum = bool(False)
for v in vars:
if sum and v:
return False
else:
sum = sum or v
return sum
TrueとFalseのブール値ではなく、1と0を使って作業していることがあります。この場合、xorは次のように定義できます。
z = (x + y) % 2
次の真理値表があります。
x
|0|1|
-+-+-+
0|0|1|
y -+-+-+
1|1|0|
-+-+-+
これはどう?
(not b and a) or (not a and b)
a
がfalseの場合、b
を返します。b
がfalseの場合、はa
を返します。
はそうでなければFalse
を与えるでしょう
あるいは、Python 2.5以降の3進表現では、
(False if a else b) if b else a
ここで提案されている実装の中には、場合によってはオペランドを繰り返し評価するものがあります。これは意図しない副作用につながる可能性があるため、避ける必要があります。
とは言っても、xor
またはTrue
を返すFalse
の実装はかなり単純です。特に2つ以上のオペランドがある場合は、どちらのオペランドを選択するべきかについて合意が得られないため、可能であればオペランドの1つを返すものははるかに扱いにくいものです。たとえば、xor(None, -1, [], True)
はNone
、[]
、またはFalse
を返すべきですか。私は各答えが何人かの人々に最も直感的なものとして見えると思います。
TrueまたはFalseのどちらの結果にも、最大5つの選択肢があります。最初のオペランドを返す(値の最終結果と一致する場合は、それ以外の場合はブール値)最後のオペランド(if ... 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()
シンプルでわかりやすい
sum( (bool(a), bool(b) ) == 1
排他的な選択があなたが求めているものであれば、それは複数の引数に拡張することができます。
sum( bool(x) for x in y ) == 1
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))
これは、2つ(またはそれ以上)の変数の排他的論理排他XORを取得します。
str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
any([str1, str2]) and not all([str1, str2])
この設定の最初の問題は、リスト全体を2回トラバースし、少なくとも1つの要素を2回チェックすることです。そのため、コードの理解度が上がる可能性がありますが、速度を上げるのには役立ちません(これは、ユースケースによっては無視できるほど異なる場合があります)。
この設定の2番目の問題は、変数の数に関係なく、排他性をチェックすることです。これは最初は機能と見なすことができますが、最初の問題は変数の数が増えるにつれてさらに重要になります(それらが増えた場合)。
XORはoperator.xor
に実装されています。
私も含め多くの人々は、nが可変であるn入力xor回路のように振舞うxor
関数を必要としています。 ( 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
XorはPythonの^
です。それは戻ります:
__xor__
を実装するクラスに対するユーザー定義の結果。とにかくそれらを文字列に使用するつもりなら、それらをbool
にキャストすることはあなたの操作を明確にします(あなたはset(str1) ^ set(str2)
を意味するかもしれません)。
Pythonで2つ以上の変数の論理xorを取得するには:
^
またはoperator.xor
)を使用します例えば、
bool(a) ^ bool(b)
入力をブール値に変換すると、bitwisexorはlogicalxorになります。
受け入れられた答えが間違っていることに注意してください:!=
は、演算子連鎖の微妙さのため、Pythonのxorと同じではありません。
たとえば、!=
を使用する場合、以下の3つの値のxorは間違っています。
True ^ False ^ False # True, as expected of XOR
True != False != False # False! Equivalent to `(True != False) and (False != False)`
(追記:受け入れられた回答を編集してこの警告を含めることを試みましたが、私の変更は拒否されました。)
Pythonには排他的論理和演算子があります。^
です。
したがって、どのライブラリにも、自分でホイールを発明する必要もありません。
>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False