33

ブール値の任意のリストが与えられた場合、そのうちの 1 つだけが真であると判断する最もエレガントな方法は何ですか?

最も明白なハックは型変換です: それらを0forfalse1forに変換してからtrue合計し、 を返しsum == 1ます。

実際にブール論理を使用して、intに変換せにこれを行う方法があるかどうかを知りたいです。

(これは些細な、idk、長い 1 週間であるべきだと思われます)

編集:明らかでない場合、これはコードゴルフ/理論的な質問です。PROD コードでの型変換 / int 加算の使用に大騒ぎしているわけではありません。

Edit2:申し訳ありませんが、今週は長い週であり、私は自分自身をうまく説明していません. これを試してみましょう:

ブール論理では、すべてのブール値が true の場合、ブール値のコレクションの AND は true になり、それらの少なくとも 1 つが true の場合、コレクションの OR は true になります。ちょうど 1 つのブール値が true の場合に true になる論理構造はありますか? XOR は、たとえば 2 つのブール値のコレクションの場合ですが、それ以上になると失敗します。

4

18 に答える 18

13

あなたの例ではおそらく実用的な価値はありませんが、実際にはブール論理のみを使用してこれを達成できます。ブール値のバージョンは、単に真の値の数を数えるよりもはるかに複雑です。

とにかく、知的好奇心を満たすために、ここに行きます。まず、一連の XOR を使用するというアイデアは優れていますが、道半ばです。任意の 2 つの変数xyについて、

x⊻y _ _

それらの 1 つだけが true の場合は常に true です。ただし、3 番目の変数zを追加すると、これは当てはまりません。

xyz

最初の部分xyは、 xyのいずれかが真である場合でも真です。xまたはyのいずれかが true の場合、式全体が true になるにはzが false である必要があります。これが必要です。しかし、 xyの両方が true の場合はどうなるか考えてみてください。x ⊻ yは false ですが、 zもtrue の場合、式全体が true になる可能性があります。したがって、1 つの変数または 3 つすべてが true でなければなりません。一般に、XOR のチェーンであるステートメントがある場合、奇数の変数が true である場合に true になります。

1 は奇数なので、これは役に立つかもしれません。もちろん、奇数の真理をチェックするだけでは十分ではありません。さらに、真の変数が 1 つだけであることを確認する必要があります。これは、2 つの変数のすべてのペアを取得し、それらが両方とも真ではないことを確認することにより、ペアごとに行うことができます。これら 2 つの条件を組み合わせると、変数が true の場合に 1 つだけが保証されます。

以下は、アプローチを説明するための小さな Python スクリプトです。

from itertools import product

print("x|y|z|only_one_is_true")
print("======================")
for x, y, z in product([True, False], repeat=3):
    uneven_number_is_true = x ^ y ^ z
    max_one_is_true = (not (x and y)) and (not (x and z)) and (not (y and z))
    only_one_is_true = uneven_number_is_true and max_one_is_true
    print(int(x), int(y), int(z), only_one_is_true)

そして、これが出力です。

x|y|z|only_one_is_true
======================
1 1 1 偽
1 1 0 偽
1 0 1 偽
1 0 0 真
0 1 1 偽
0 1 0 真
0 0 1 真
0 0 0 偽
于 2015-10-21T20:19:11.413 に答える
5

明確にした後、ここに整数はありません。

 bool IsExactlyOneBooleanTrue( bool *boolAry, int size )
    {
      bool areAnyTrue = false;
      bool areTwoTrue = false;
      for(int i = 0; (!areTwoTrue) && (i < size); i++) {
        areTwoTrue = (areAnyTrue && boolAry[i]);
        areAnyTrue |= boolAry[i];
      }
      return ((areAnyTrue) && (!areTwoTrue));
    }
于 2013-02-15T04:49:14.720 に答える
4

私たちが探しているこの「操作」は、ほとんどの言語でブール値の AND や OR と同様にショートカット可能であるとは誰も言いませんでした。Java での実装は次のとおりです。

public static boolean exactlyOneOf(boolean... inputs) {
    boolean foundAtLeastOne = false;
    for (boolean bool : inputs) {
        if (bool) {
            if (foundAtLeastOne) {
                // found a second one that's also true, shortcut like && and ||
                return false;
            }
            foundAtLeastOne = true;
        }
    }
    // we're happy if we found one, but if none found that's less than one
    return foundAtLeastOne;
}
于 2016-09-05T17:01:31.043 に答える
4

確かに、次のようなことを行うことができます(言語について言及していないため、疑似コード):

found = false;
alreadyFound = false;
for (boolean in booleans):
    if (boolean):
        found = true;
        if (alreadyFound):
            found = false;
            break;
        else:
            alreadyFound = true;
return found;
于 2013-02-15T04:35:48.637 に答える
4

単純なブール論理では、目的を達成できない場合があります。あなたが求めているのは、真理値だけでなく、追加情報 (この場合はカウント) に基づく真理評価であるためです。ただし、ブール値の評価はバイナリ ロジックであり、オペランド自体以外には依存できません。また、オペランドの組み合わせは 4 通りありますが、結果は 2 つしかないため、リバース エンジニアリングを行って真値が与えられたオペランドを見つける方法はありません。false が与えられた場合、それが F ^ F によるものなのか T ^ T によるものなのかを判断して、それに基づいて次の評価を決定できますか?

于 2013-02-15T13:31:44.537 に答える
2

たとえばHaskellのように、再帰を使用すると非常にうまく実行できます。

-- there isn't exactly one true element in the empty list
oneTrue [] = False 
-- if the list starts with False, discard it
oneTrue (False : xs) = oneTrue xs
-- if the list starts with True, all other elements must be False
oneTrue (True : xs) = not (or xs)
于 2013-02-15T06:56:18.927 に答える
2

booleanList.Where(y => y).Count() == 1;

于 2013-02-15T04:49:42.687 に答える
0

OK、もう一度試してください。さまざまなブール値b[i]を呼び出し、それらのスライス(配列の範囲)を呼び出しますb[i .. j]。関数none(b[i .. j])を定義しますjust_one(b[i .. j])(必要に応じて、再帰的定義を代用して明示的な式を取得できます)。論理演算にC表記を使用します(&&is and、||is or、^xor(実際にはCではない)で!はありません):

none(b[i .. i + 1]) ~~> !b[i] && !b[i + 1]
just_one(b[i .. i + 1]) ~~> b[i] ^ b[i + 1]

そして再帰的に:

none(b[i .. j + 1]) ~~> none(b[i .. j]) && !b[j + 1]
just_one(b[i .. j + 1] ~~> (just_one(b[i .. j]) && !b[j + 1]) ^ (none(b[i .. j]) && b[j + 1])

そして、あなたはに興味がありjust_one(b[1 .. n])ます。

表情はひどいものになります。

楽しむ!

于 2013-02-16T03:56:27.467 に答える
0

その python スクリプトはうまく機能します。使用するワンライナーは次のとおりです。

((x ∨ (y ∨ z)) ∧ (¬(x ∧ y) ∧ (¬(z ∧ x) ∧ ¬(y ∧ z))))

于 2016-04-18T10:46:43.020 に答える
0

Python: 例を使用して見てみましょう... 手順:

  1. 以下の関数exactly_one_toppingは3つのパラメータを取ります

  2. それらの値を としてリストに格納しますTrueFalse

  3. カウントが正確に 1 であることを確認して、真の値が 1 つだけ存在するかどうかを確認します。

def exactly_one_topping(ketchup, mustard, onion):
    
  args = [ketchup,mustard,onion]
  if args.count(True) == 1:   # check if Exactly one value is True
      return True
  else:
      return False
于 2021-04-14T08:56:05.517 に答える
-1

数えずに真の数をどのように数えたいですか?確かに、あなたは次のような厄介なことをすることができます(C構文、私のPythonはひどいです):

for(i = 0; i < last && !booleans[i]; i++)
     ;
if(i == last)
     return 0;  /* No true one found */
/* We have a true one, check there isn't another */
for(i++; i < last && !booleans[i]; i++)
     ;
if(i == last)
     return 1; /* No more true ones */
else
     return 0; /* Found another true */ 

勝利(もしあれば)がわずかで、読みやすさが悪いことにあなたは同意するでしょう。

于 2013-02-15T05:04:46.840 に答える
-4

このようにできます:-

if (A=true or B=true)and(not(A=true and B=true)) then
<enter statements>
end if
于 2016-12-14T09:21:39.457 に答える