質問
私は5つのブール値のセットを持っています。これらの2つ以上が該当する場合、私は特定の機能をexcecuteたいです。あなたは私が単一の場合()文でこの状態を確認できるようになるものと考えることができる最もエレガントな方法は何ですか?対象言語は、C#であるが、私は(私たちは、特定の組み込み関数について話していない限り)だけでなく、他の言語でのソリューションに興味があります。
一つの興味深いオプションは、バイトでブール値を格納し右シフトを行うと、元のバイトを比較することです。 if(myByte && (myByte >> 1))
ような何かしかし、これは(bitArray経由?)バイトに別々のブール値に変換が必要になり、それはビット(しゃれが意図した)不器用なようだ... の[編集]申し訳ありませんが、のif(myByte & (myByte - 1))
されている必要がありますの[/編集]
注:これは、もちろん「さらに横」古典「人口数」、または「ハミング重み」プログラミングの問題に非常に近いです - しかし、全く同じではありません。私はそれが複数ある場合にのみ、設定されているどのように多くのビットを知っている必要はありません。私の希望は、これを達成するための非常に簡単な方法があるということです。
解決
どの程度
if ((bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) +
(bool4? 1:0) + (bool5? 1:0) > 1)
// do something
や一般化の方法は次のようになります...
public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
{
int trueCnt = 0;
foreach(bool b in bools)
if (b && (++trueCnt > threshold))
return true;
return false;
}
や他の回答により示唆されるようにLINQを使用します:
public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
{ return bools.Count(b => b) > threshold; }
EDIT(ジョエルCoehoorn提案を追加します。 (.NET 2.xで以降)
public void ExceedsThreshold<T>(int threshold,
Action<T> action, T parameter,
IEnumerable<bool> bools)
{ if (ExceedsThreshold(threshold, bools)) action(parameter); }
または.NET 3.5以降ます:
public void ExceedsThreshold(int threshold,
Action action, IEnumerable<bool> bools)
{ if (ExceedsThreshold(threshold, bools)) action(); }
または
IEnumerable<bool>
への拡張として
public static class IEnumerableExtensions
{
public static bool ExceedsThreshold<T>
(this IEnumerable<bool> bools, int threshold)
{ return bools.Count(b => b) > threshold; }
}
使用量は次のようになります:
var bools = new [] {true, true, false, false, false, false, true};
if (bools.ExceedsThreshold(3))
// code to execute ...
他のヒント
私は、LINQのバージョンを書くつもりだったが、5かそこらの人々はそれに私を打ちます。しかし、私は本当にのparamsアプローチのようにアップし、手動で新しい配列することを避けるために。だから私は、明らかなLinqnessと交換体とRPの回答に基づいて、最高のハイブリッドがあると思います:
public static int Truth(params bool[] booleans)
{
return booleans.Count(b => b);
}
読み、そして使用するために美しく明確ます:
if (Truth(m, n, o, p, q) > 2)
これは、このケースでは、実際には非常にきれいである義務LINQの答えは、時間です。
var bools = new[] { true, true, false, false, false };
return bools.Count(b => b == true) > 1;
私はint型との和にそれらをキャストします。
あなたが理解しやすいという利点があり、超タイトな内側のループにしている場合を除きます。
私は、ブール値の任意の番号を受信する機能を記述します。それは本当であるそれらの値の数を返します。あなたが何かを肯定する必要がある値の数の結果を確認します。
は賢い、それは明確ではない作るために懸命に働きます!
private int CountTrues( params bool[] booleans )
{
int result = 0;
foreach ( bool b in booleans )
{
if ( b ) result++;
}
return result;
}
は、
のようにそれを行うことができますif (bool1 || bool2 || bool3 || bool4 || bool5)
あなたが複数(2以上)がtrueに等しいブール値が必要な場合は、あなたが試すことができます。
int counter = 0;
if (bool1) counter++;
if (bool2) counter++;
if (bool3) counter++;
if (bool4) counter++;
if (bool5) counter++;
if (counter >= 2) //More than 1 boolean is true
だけではなく、5百万人があった場合は(カウントを避けるため)、代わりにこれを行うことができます...
public static bool MoreThanOne (IEnumerable<bool> booleans)
{
return booleans.SkipWhile(b => !b).Skip(1).Any(b => b);
}
あなたのフラグが1語、その後<のhref = "https://stackoverflow.com/questions/377990/elegantly-determine-if-more-than-one-boolean-is-true/379947#379947にパックされている場合動作しますの「>マイケル・バリのソリューション。しかし、ループは必要ありません。
int moreThanOneBitSet( unsigned int v)
{
return (v & (v - 1)) != 0;
}
例
v (binary) | v - 1 | v&(v-1) | result
------------+-------+---------+--------
0000 | 1111 | 0000 | false
0001 | 0000 | 0000 | false
0010 | 0001 | 0000 | false
0011 | 0010 | 0010 | true
.... | .... | .... | ....
1000 | 0111 | 0000 | false
1001 | 1000 | 1000 | true
1010 | 1001 | 1000 | true
1011 | 1010 | 1010 | true
1100 | 1011 | 1000 | true
1101 | 1100 | 1100 | true
1110 | 1101 | 1100 | true
1111 | 1110 | 1110 | true
Vilx-sのバージョンよりも短く、醜います:
if (((a||b||c)&&(d||e))||((a||d)&&(b||c||e))||(b&&c)) {}
私の頭の上、この特定の例のための迅速なアプローチから。あなたはint型(0または1)にブール値を変換することができます。その後、サームをループには、それらを追加します。場合、結果は> = 2、あなたはあなたの関数を実行することができます。
、いくつかの穴は、この問題のように、その中にあります。
のカウントを行うことは一般的に細かいですが、アイテムがあなたのカウント取得/計算に時間がかかる際に問題になることができます。
あなただけのいずれかのためにチェックしたい場合は、任意の()拡張メソッドは罰金ではありませんが、あなたがチェックしたい場合は、少なくとも何もそれを行うと怠惰になる機能であり組み込まれてます。
最後に、私は、リスト内の項目の特定の数は、少なくともある場合にtrueを返すように機能を書いています。
public static bool AtLeast<T>(this IEnumerable<T> source, int number)
{
if (source == null)
throw new ArgumentNullException("source");
int count = 0;
using (IEnumerator<T> data = source.GetEnumerator())
while (count < number && data.MoveNext())
{
count++;
}
return count == number;
}
を使用するには:
var query = bools.Where(b => b).AtLeast(2);
この結果を返す前に、すべての項目を評価する必要がないというメリットがあります。
[プラグイン]私のプロジェクト、 NExtension には少なくとも、[最大とあなたに混在させることができオーバーライドが含まれています少なくとも/ほとんどのチェックと述語。 【/プラグ
int型にキャストして動作するはず加算するが、それは少し醜いだと一部の言語ではできないことがあります。
どのように
のようなものについてint count = (bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0);
それとも、スペースを気にしないならば、あなただけの真理値表を事前に計算し、指標としてboolsを使用することができます:
if (morethanone[bool1][bool2][bool3][bool4][bool5]) {
... do something ...
}
私はのparams引数を使用して、このような何かをするでしょう。
public void YourFunction()
{
if(AtLeast2AreTrue(b1, b2, b3, b4, b5))
{
// do stuff
}
}
private bool AtLeast2AreTrue(params bool[] values)
{
int trueCount = 0;
for(int index = 0; index < values.Length || trueCount >= 2; index++)
{
if(values[index])
trueCount++;
}
return trueCount > 2;
}
if (NumberOfTrue(new List<bool> { bool1, bool2, bool3, bool4 }) >= 2)
{
// do stuff
}
int NumberOfTrue(IEnumerable<bool> bools)
{
return bools.Count(b => b);
}
未正確にかなり...しかし、ここでそれを行うための別の方法があります:
if (
(a && (b || c || d || e)) ||
(b && (c || d || e)) ||
(c && (d || e)) ||
(d && e)
)
私は今、非常に短いはるかに優れたものを持っている!
bool[] bools = { b1, b2, b3, b4, b5 };
if (bools.Where(x => x).Count() > 1)
{
//do stuff
}
私はC ++ 11可変長引数テンプレート答えを与えたいと思っています。
template< typename T>
T countBool(T v)
{
return v;
}
template< typename T, typename... Args>
int countBool(T first, Args... args)
{
int boolCount = 0;
if ( first )
boolCount++;
boolCount += countBool( args... );
return boolCount;
}
次のように単にboolsの数をカウントするかなりエレガント方法を作成し、それを呼び出す。
if ( countBool( bool1, bool2, bool3 ) > 1 )
{
....
}
は、ほとんどの言語では真の非ゼロ値に相当します。私はあなたのための正確な構文を持っていますが、擬似コードでは、どの程度ありません。
if ((bool1 * 1) + (bool2 * 1) + (bool3 * 1) > 2)
{
//statements here
}
あなたが唯一の5つの異なる値を持っている場合は、あなたが簡単に短いか、int型へのビットを梱包し、それがゼロまたは1ビットの回答のいずれかがあるかどうかを確認することでテストを行うことができます。あなたが得ることができる唯一の無効な数値は以下のようになります..
0x 0000 0000 0x 0000 0001 0x 0000 0010 0x 0000 0100 0x 0000 1000 0x 0001 0000
これは、あなたを検索ルックアップテーブルにそれらを置くための6つの値を与え、それがそこにない場合、あなたはあなたの答えを持っています。
このはあなたに簡単な答えを与えています。
public static boolean moreThan1BitSet(int b) { final short multiBitLookup[] = { 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if(multiBitLookup[b] == 1) return false; return true; }
これは8ビットを過ぎてうまくスケールしませんが、あなたは唯一の5つがあります。
もし((b1.CompareTo(偽)+ b2.CompareTo(偽)+ b3.CompareTo(偽)+ ...)> 1)
//それらのいずれかに該当しているより多くのよりも、
...
他の
...
あなたが言及した。
一つの興味深いオプションは、バイトでブール値を格納することで、 右シフトを行うと、元のバイトを比較します。
if (myByte && (myByte >> 1))
ような何か。
私は(式が有効なC#ではないので、少なくともCセマンティクスを使用して)式は、あなたが望む結果を与えるとは思わない:
(myByte == 0x08)
場合は、式は1ビットだけセットがありますにもかかわらず、trueを返します。
if (myByte & (myByte >> 1))
式が設定され2ビットが存在するにもかかわらず、falseを返します場合は、その後、「(myByte == 0x0a)
」を意味します。
しかし、ここでは、ワードのビット数をカウントするためのいくつかの技術であります
あなたは検討するかもしれない変化がカーニハンのカウント方法を使用することですが、あなたは唯一つ以上のビットセットがありますかどうかを知る必要があるため、早期救済します
int moreThanOneBitSet( unsigned int v)
{
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v && (c <= 1); c++)
{
v &= v - 1; // clear the least significant bit set
}
return (c > 1);
}
もちろん、ルックアップテーブルを使用すると、どちらか悪い選択肢ではありません。
私は最近、私はそれらの1つだけが一度に本当だったことを確認するために必要な3つのブール値を、持っていたこの同じ問題を、持っていました。次のようにこのために私は、XOR演算子を使用します:
bool a = true;
bool b = true;
bool c = false;
if (a || b || c)
{
if (a ^ b ^ c){
//Throw Error
}
}
aとbの両方が真であるように、このコードは、エラーがスローされます。
参考: http://www.dotnetperls.com/xor の
私は誰もが、この戦略の任意のピット滝を知っているならば、私に知らせてくださいC#でXOR演算子を発見しました。