If the statement is 'or', but NOT 'and'

In C Sharp, how can I configure an if statement that checks if one of several conditions is true? This should be only one of the conditions if the value is zero or two or more true. If must be false.

+7
source share
6 answers

You can write a helper method. This has the advantage that short circuits, only evaluating exactly as much as necessary,

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; } 
+9
source

You can use the layout of your logic gates in a bool sequence, and then apply LINQ:

 bool[] conditions = new bool[] { cond1, cond2, cond3, cond4 }; bool singleTrue = conditions.Count(cond => cond) == 1; 

Only for two logical objects, exclusive or significantly simplified:

 bool singleTrue = cond1 != cond2; 

Change In order to achieve an on-demand evaluation and short circuit, we need to push our bool sequence to the Func<bool> sequence (where each element is a function delegate encapsulating the condition estimate):

 IEnumerable<Func<bool>> conditions = // define sequence here int firstTrue = conditions.IndexOf(cond => cond()); bool singleTrue = firstTrue != -1 && conditions.Skip(firstTrue + 1).All(cond => !cond()); 

The above snippet assumes the existence of a predicate-based IndexOf operator, which is not available in the current version of LINQ, but can be defined as an extension method, for example:

 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; } 

Example data for testing (a breakpoint can be set for each false or true for evaluation):

 IEnumerable<Func<bool>> conditions = new Func<bool>[] { () => false, () => true, () => false, () => false, }; 
+5
source
 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) { } 

Linq implementation of Jason method signature:

 public static bool IsExactlyOneTrue(IEnumerable<Func<bool>> conditions) { int passingConditions = conditions .Where(x => x()) // .Take(2) //optimization .Count(); return passingConditions == 1; } 
+5
source

For simplicity, you can just save the counter:

 int totalTrue = 0; if (A) totalTrue++; if (B) totalTrue++; if (C) totalTrue++; ... return (1 == totalTrue); 
+4
source

I think that would do the trick

  int i= 0; if ( (!A || ++i <= 1) && (!B || ++i <= 1) && (!C || ++i <= 1) && ... && (i == 1)) 

If I had not been mistaken in this, this if would be false as soon as i > 1 . If i never increases and we reach the last condion, it will be false since i == 0

+2
source

Most of these answers will work and have "good performance." But the simplest answer is:

 if( (A & !(B || C)) || (B & !(A || C)) || (C & !(A || B)) ) { ... } 

You end up evaluating A / B / C more than once, so this is really useful when you have simple bools.

0
source

All Articles