ブール値の任意のリストが与えられた場合、exactlyそれらの1つがtrueであると判断する最もエレガントな方法は何ですか?
最も明らかなハックは型変換です。それらをfalse
の場合は0
に、true
の場合は1
に変換し、それらを合計してsum == 1
を返します。
これをなしでintに変換する方法があるかどうか知りたい実際にはブール論理を使用。
(これは簡単な、idk、長い週のようです)
編集:明らかでない場合は、これはコードゴルフ/理論的な問題です。私はPRODコードで型変換/ intを使用することに夢中ですが、それなしでそれを行う方法があるかどうかだけに興味があります。
Edit2:申し訳ありませんが、1週間が長く、説明がうまくいきません。これを試してみましょう:
ブール論理では、すべてのブール値がtrueの場合、ブール値のコレクションのAND演算はtrueになり、少なくとも1つがtrueの場合、コレクションのOR演算はtrueになります。ブール値が1つだけtrueの場合にtrueになる論理構造はありますか? XORは、たとえば2つのブール値のコレクションの場合ですが、それ以上の場合はフォールオーバーします。
単純なブールロジックでは、希望どおりの結果が得られない場合があります。あなたが求めているのは真理値だけでなく追加情報(この場合は数)にも基づいた真理評価だからです。ただし、ブール評価はバイナリロジックであり、オペランド自体にのみ依存することはできません。そして、真理値を与えられたオペランドを見つけるためにリバースエンジニアリングする方法はありません。なぜなら、オペランドの可能な組み合わせは4つあるかもしれないが、結果は2つしかないからです。偽が与えられた場合、それがあなたのケースのF ^ FまたはT ^ Tのせいかどうかがわかりますか?.
これは実際にはブール論理のみを使用して実現できますが、例ではそれの実用的な価値はおそらくないでしょう。ブールバージョンは、単に真の値の数を数えるよりもはるかに複雑です。
とにかく、知的好奇心を満たすために、ここに行きます。まず、一連のXORを使用するという考えは良いですが、それでは半分しか得られません。 2つの変数xとyの場合、
x⊻y
どちらか一方が真である場合は常に真です。ただし、3番目の変数zを追加した場合、これは当てはまりません。
x⊻y⊻z
最初の部分x⊻yは、xとyはtrueです。 xまたはyのいずれかがtrueの場合、zはfalseである必要があります表現全体が真実であるために、これが私たちの望みです。ただし、xとyの両方がtrueの場合はどうなるかを考えてみましょう。次に、x⊻yはfalseですが、zも同様です。したがって、1つの変数または3つすべてが真でなければなりません。一般に、XORのチェーンであるステートメントがある場合、変数の不均一な数が真であれば真になります。
1つは不均一な数であるため、これは役立つ場合があります。もちろん、不均等な数の真実をチェックするだけでは十分ではありません。さらに、1つの変数のみがtrueであることを確認する必要があります。これは、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 False 1 1 0偽 1 0 1偽 1 0 0真 0 1 1偽 0 1 0真 0 0 1真 0 0 0偽
あなたの説明の後、ここでは整数はありません。
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));
}
私たちが探しているこの「操作」は、ブール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;
}
それは再帰で非常にうまく行うことができます。ハスケルの
-- 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)
現在では多数の読み取りが行われているため、ここでは簡単なクリーンアップと追加情報を提供します。
最初の変数のみが真であるか、2番目の変数だけが真であるか、...、またはn番目の変数のみであるかを尋ねます。
x1 & !x2 & ... & !xn |
!x1 & x2 & ... & !xn |
...
!x1 & !x2 & ... & xn
このアプローチはO(n ^ 2)でスケーリングされ、最初の正の一致が見つかると評価は停止します。したがって、一致する可能性が高い場合に適しています。
少なくとも合計で1つの変数が真であるかどうかを尋ねます。さらに、すべてのペアをチェックして最大で 1つの真の変数を含める(Anders Johannsenの答え)
(x1 | x2 | ... | xn) &
(!x1 | !x2) &
...
(!x1 | !xn) &
(!x2 | !x3) &
...
(!x2 | !xn) &
...
可能なペアの数により、このオプションはO(n ^ 2)でもスケーリングされます。遅延評価は、最初の反例の後で式を停止します。したがって、否定的な一致がある可能性が高い場合は、それが推奨されます。
このオプションには減算が含まれるため、制限された設定に対してnoは有効な回答です。それにもかかわらず、値をループすることは無制限のステッティングでは最も有益な解決策ではないかもしれないと主張しています。
X1 ... xnを2進数xとして扱います。 1を減算してから、結果のANDを計算します。出力はゼロです<=> x1 ... xnには最大で1つの真の値が含まれます。 (古い「2の累乗をチェックする」アルゴリズム)
x 00010000
x-1 00001111
AND 00000000
ビットがそのようなビットボードに既に格納されている場合、これはループよりも有益な場合があります。ただし、これは読みやすさを損ない、利用可能なボードの長さによって制限されることに注意してください。
意識を高めるための最後の注意:今のところ、この種のアルゴリズムの質問に的を絞ったコンピュータサイエンスと呼ばれるスタック交換が存在します
これを行う1つの方法は、ペアワイズAND
を実行し、チェーンOR
でペアワイズ比較のいずれかがtrueを返したかどうかを確認することです。 pythonでは、
from itertools import combinations
def one_true(bools):
pairwise_comp = [comb[0] and comb[1] for comb in combinations(bools, 2)]
return not any(pairwise_comp)
このアプローチは、任意の長さのリストに簡単に一般化できますが、非常に長いリストの場合、可能なペアの数は急速に増加します。
確かに、次のようなことを行うことができます(言語について言及しなかったため、疑似コード):
found = false;
alreadyFound = false;
for (boolean in booleans):
if (boolean):
found = true;
if (alreadyFound):
found = false;
break;
else:
alreadyFound = true;
return found;
booleanList.Where(y => y).Count()== 1;
そのpythonスクリプトはうまく機能します。これが使用する1行のコードです。
((x∨(y∨z))∧(¬(x∧y)∧(¬(z∧x)∧¬(y∧z))))
どのようにしたいですかcountどれだけがtrueですかcounting?確かに、(C構文、my 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 */
勝利(もしあれば)がわずかであり、読みやすさが悪いことに同意するでしょう。
はい、もう一度お試しください。さまざまなブール値_b[i]
_を呼び出し、それらのスライス(配列の範囲)_b[i .. j]
_を呼び出します。関数none(b[i .. j])
およびjust_one(b[i .. j])
を定義します(必要に応じて、再帰的な定義を代入して明示的な式を取得できます)。論理演算にC表記を使用します(_&&
_ is and、_||
_ is or、_^
_ for xor(not not in C)、_!
_ is not):
_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])
に興味があります。
式は恐ろしいことが判明します。
楽しんで!
ループなしでは不可能です。 Java実装のBitSet cardinality()を確認してください。 http://fuseyism.com/classpath/doc/Java/util/BitSet-source.html