C Sharpで、いくつかの条件の1つが真であるかどうかをチェックするifステートメントを設定するにはどうすればよいですか?条件の1つだけである必要があり、0または2つ以上が真の場合、ifは偽である必要があります。
6 に答える
ヘルパーメソッドを書くことができます。これには、短絡し、必要な数だけを正確に評価するという利点があります。
public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions) {
bool any = false;
foreach (var condition in conditions) {
bool result = condition();
if (any && result) {
return false;
}
any = any | result;
}
return any;
}
List<Func<Customer, bool>> criteria = new List<Func<Customer, bool>>();
criteria.Add(c => c.Name.StartsWith("B"));
criteria.Add(c => c.Job == Jobs.Plumber);
criteria.Add(c => c.IsExcellent);
Customer myCustomer = GetCustomer();
int criteriaCount = criteria
.Where(q => q(myCustomer))
// .Take(2) // optimization
.Count()
if (criteriaCount == 1)
{
}
JasonのメソッドシグネチャのLinq実装:
public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions)
{
int passingConditions = conditions
.Where(x => x())
// .Take(2) //optimization
.Count();
return passingConditions == 1;
}
ブール値をbool
シーケンスに構成してから、LINQを適用できます。
bool[] conditions = new bool[] { cond1, cond2, cond3, cond4 };
bool singleTrue = conditions.Count(cond => cond) == 1;
たった2つのブール値の場合、排他的論理和またははるかに単純になります。
bool singleTrue = cond1 != cond2;
編集:オンデマンド評価と短絡を実現するにはbool
、シーケンスをシーケンスに昇格させる必要がありFunc<bool>
ます(各要素は条件の評価をカプセル化する関数デリゲートです)。
IEnumerable<Func<bool>> conditions = // define sequence here
int firstTrue = conditions.IndexOf(cond => cond());
bool singleTrue = firstTrue != -1 &&
conditions.Skip(firstTrue + 1).All(cond => !cond());
上記のスニペットは、述語ベースのIndexOf
演算子の存在を前提としています。これは、現在のバージョンのLINQでは使用できませんが、次のような拡張メソッドとして定義できます。
public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
int i = 0;
foreach (T element in source)
{
if (predicate(element))
return i;
i++;
}
return -1;
}
テスト用のサンプルデータ(ブレークポイントはそれぞれに設定されるfalse
かtrue
、評価に続く場合があります):
IEnumerable<Func<bool>> conditions = new Func<bool>[]
{
() =>
false,
() =>
true,
() =>
false,
() =>
false,
};
簡単にするために、実行中のカウントを維持することができます。
int totalTrue = 0;
if (A) totalTrue++;
if (B) totalTrue++;
if (C) totalTrue++;
...
return (1 == totalTrue);
これでうまくいくと思います
int i= 0;
if ( (!A || ++i <= 1) &&
(!B || ++i <= 1) &&
(!C || ++i <= 1) &&
... &&
(i == 1))
私がこれについて間違っていると思わなかった場合、これif
はすぐに誤りになりますi > 1
。がインクリメントされず、最後の条件に到達した場合i
、以降はfalseになります。i == 0
これらの回答のほとんどは機能し、「良好なパフォーマンス」を発揮します。しかし、最も簡単な答えは次のとおりです。
if( (A & !(B || C)) ||
(B & !(A || C)) ||
(C & !(A || B)) )
{
...
}
A / B / Cを複数回評価することになりますので、これは単純なブールがある場合にのみ実際に役立ちます。