web-dev-qa-db-ja.com

Pythonで2つの変数の論理和をどうやって求めるのですか?

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'
535
Zach Hirsch

すでにブール値への入力を正規化しているのであれば、!=はxorです。

bool(a) != bool(b)
1019
A. Coady

Xorの定義を他の論理演算から計算するためにいつでも使用できます。

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

しかし、これは私にとっては少し冗長すぎるため、一見したところ特に明確ではありません。それを行う別の方法は、次のとおりです。

bool(a) ^ bool(b)

2つのブール値のxor演算子は論理xorです(ビット単位のint型とは異なり)。 boolは単なるint のサブクラスなので、これは理にかなっていますが、値01を持つように実装されています。ドメインが0および1に制限されている場合、論理xorはビットごとのxorと同等です。

そのため、logical_xor関数は次のように実装されます。

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

Python-3000メーリングリストの Nick Coghlanの功績による

414
Zach Hirsch

operator モジュールで、排他的論理和はすでにPythonに組み込まれています。

from operator import xor
xor(bool(a), bool(b))
155
singingwolfboy

Zach の説明のとおり、次のものを使用できます。

xor = bool(a) ^ bool(b)

個人的には、少し違った方言を好みます。

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

この方言は、私が学校で学んだ論理的な図表作成言語からヒントを得たもので、「OR」は≥1(1以上)を含むボックスで、「XOR」は=1を含むボックスで表されます。

これには、排他的または複数のオペランドに対して正しく実装するという利点があります。

  • "1 = a ^ b ^ c ..."は、真のオペランドの数が奇数であることを意味します。この演算子は「パリティ」です。
  • "1 = a + b + c ..."は、1つのオペランドが真であることを意味します。これは「排他的論理和」であり、「他のものを除外したもの」を意味します。
35
ddaa
  • Python論理orA or Bbool(A)AであればTrueを返し、そうでなければBを返します
  • Python論理andA and Bbool(A)AであればFalseを返し、そうでなければBを返します

その考え方の大部分を維持するために、私の論理的xor定義は次のようになります。

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

そのようにして、ab、またはFalseを返すことができます。

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

私はいくつかの方法を試しましたが、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
17
Rugnar

やりがいのあるスレッド:

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

私が書いた英語をすみません、それは私の生まれた言語ではありません。

よろしく。

8
Agustin Marcos

私はこれが遅れていることを知っています、しかし私は考えを持っていました、そしてそれはただ文書化のために、価値があるかもしれません。おそらくこれでうまくいくでしょう:np.abs(x-y)アイデアは

  1. x = True = 1かつy = False = 0の場合、結果は| 1-0 | = 1 = Trueになります。
  2. x = False = 0かつy = False = 0の場合、結果は| 0-0 | = 0 = Falseになります。
  3. x = True = 1かつy = True = 1の場合、結果は| 1-1 | = 0 = Falseになります。
  4. x = False = 0かつy = True = 1の場合、結果は| 0-1 | = 1 = Trueになります。
7

排他的論理和は次のように定義されます。

def xor( a, b ):
    return (a or b) and not (a and b)
7
S.Lott

変数引数を使用し、真理値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
7
micdah

TrueとFalseのブール値ではなく、1と0を使って作業していることがあります。この場合、xorは次のように定義できます。

z = (x + y) % 2

次の真理値表があります。

     x
   |0|1|
  -+-+-+
  0|0|1|
y -+-+-+
  1|1|0|
  -+-+-+
6
Steve L

これはどう?

(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
6
Markus Jarderot

ここで提案されている実装の中には、場合によってはオペランドを繰り返し評価するものがあります。これは意図しない副作用につながる可能性があるため、避ける必要があります。

とは言っても、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()
6

シンプルでわかりやすい

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

排他的な選択があなたが求めているものであれば、それは複数の引数に拡張することができます。

sum( bool(x) for x in y ) == 1
5
c z

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))
4
Denis Barmenkov

これは、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番目の問題は、変数の数に関係なく、排他性をチェックすることです。これは最初は機能と見なすことができますが、最初の問題は変数の数が増えるにつれてさらに重要になります(それらが増えた場合)。

4
Marc

XORはoperator.xorに実装されています。

4
lbolla

私も含め多くの人々は、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
3

XorはPythonの^です。それは戻ります:

  • 整数のビットごとのxor
  • ブールの論理和
  • セットのための排他的な和集合
  • __xor__を実装するクラスに対するユーザー定義の結果。
  • 文字列や辞書などの未定義型のTypeError。

とにかくそれらを文字列に使用するつもりなら、それらをboolにキャストすることはあなたの操作を明確にします(あなたはset(str1) ^ set(str2)を意味するかもしれません)。

2
Arthur Havlicek

Pythonで2つ以上の変数の論理xorを取得するには:

  1. 入力をブール値に変換する
  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)`

(追記:受け入れられた回答を編集してこの警告を含めることを試みましたが、私の変更は拒否されました。)

2
Arel

Pythonには排他的論理和演算子があります。^です。

したがって、どのライブラリにも、自分でホイールを発明する必要もありません。

>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False
0
Tomer Gal