Elegantly determine if more than one logical value is "true"

I have a set of five boolean values. If more than one of them is true, I want to transcend a particular function. What is the most elegant way you might think that allows me to test this condition in a single if () statement? The target language is C #, but I am also interested in solutions in other languages ​​(so far we are not talking about specific built-in functions).

One interesting option is to store Boolean in bytes, do a right shift and compare with the original byte. Something like if(myByte && (myByte >> 1)) But for this you need to convert the individual booleans to bytes (via bitArray?), And this seems a bit (pun intended) awkward ... [edit] Sorry, it should have been if(myByte & (myByte - 1)) [/ edit]

Note. This, of course, is very close to the classic problem of "counting the population", "lateral addition" or "Hamming-weight", but not quite the same. I do not need to know how many bits are set only if it is more than one. I hope there is a much easier way to do this.

+64
c # hammingweight
Dec 18 '08 at 14:27
source share
22 answers

What about

  if ((bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0) > 1) // do something 

or a generalized method would be ...

  public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools) { int trueCnt = 0; foreach(bool b in bools) if (b && (++trueCnt > threshold)) return true; return false; } 

or using LINQ as suggested by other answers:

  public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools) { return bools.Count(b => b) > threshold; } 

EDIT (add Joel Coehorn's suggestion: (in .Net 2.x and later)

  public void ExceedsThreshold<T>(int threshold, Action<T> action, T parameter, IEnumerable<bool> bools) { if (ExceedsThreshold(threshold, bools)) action(parameter); } 

or in .Net 3.5 and later:

  public void ExceedsThreshold(int threshold, Action action, IEnumerable<bool> bools) { if (ExceedsThreshold(threshold, bools)) action(); } 

or as an extension to IEnumerable<bool>

  public static class IEnumerableExtensions { public static bool ExceedsThreshold<T> (this IEnumerable<bool> bools, int threshold) { return bools.Count(b => b) > threshold; } } 

will be:

  var bools = new [] {true, true, false, false, false, false, true}; if (bools.ExceedsThreshold(3)) // code to execute ... 
+77
Dec 18 '08 at 14:37
source share
β€” -

I was about to write a version of Linq, but five or so I was beaten. But I really like the params approach to avoid having to manually create an array. Therefore, I believe that the best hybrid based on rp's answer with the body replaces the obvious Linqness:

 public static int Truth(params bool[] booleans) { return booleans.Count(b => b); } 

It is perfectly clear to read and use:

 if (Truth(m, n, o, p, q) > 2) 
+109
Dec 18 '08 at 15:53
source share

This is the time for a binding LINQ answer, which in this case is actually pretty neat.

 var bools = new[] { true, true, false, false, false }; return bools.Count(b => b == true) > 1; 
+18
Dec 18 '08 at 15:22
source share

I would just drop them into ints and summarize.

If you are not in a super-modern inner loop, this can be easily understood.

+16
Dec 18 '08 at 14:34
source share

I would write a function to get any number of booleans. This will return the number of those values ​​that are true. Check the result for the number of values ​​you need to make positive in order to do something.

Harder to make it clear, not smart!

 private int CountTrues( params bool[] booleans ) { int result = 0; foreach ( bool b in booleans ) { if ( b ) result++; } return result; } 
+6
Dec 18 '08 at 15:01
source share

If there were millions instead of 5, you could escape Count () and do it instead ...

 public static bool MoreThanOne (IEnumerable<bool> booleans) { return booleans.SkipWhile(b => !b).Skip(1).Any(b => b); } 
+5
Jun 06 '10 at 3:21
source share

If your flags are packed in one word, then Michael Burr solution will work. However, the loop is not needed:

 int moreThanOneBitSet( unsigned int v) { return (v & (v - 1)) != 0; } 

Example

  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 
+5
May 10 '11 at 15:45
source share

if you mean more than or equal to one boolean equal to true, you can do it like

 if (bool1 || bool2 || bool3 || bool4 || bool5) 

If you need more than one (2 and above) booleans equal to true, you can try

 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 
+4
Dec 18 '08 at 14:35
source share

Shorter and uglier versions of Vilx:

 if (((a||b||c)&&(d||e))||((a||d)&&(b||c||e))||(b&&c)) {} 
+4
Dec 18 '08 at 17:43
source share

from the top of the head, a quick approach for this particular example; you can convert bool to int (0 or 1). then go through the thermometer and add them up. if the result is> = 2, you can execute your function.

+2
Dec 18 '08 at 14:36
source share

Although I like LINQ, there are some holes in it like this problem.

The execution of the count is generally normal, but it can become a problem when the items that are being counted are calculated / retrieved.

The Any () extension method is great if you just want to test it, but if you want to check, at least there is no built-in function that will do this and be lazy.

At the end, I wrote a function to return true if the list contains at least a certain number of elements.

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

For use:

 var query = bools.Where(b => b).AtLeast(2); 

This is useful if you do not need to evaluate all the elements before returning the result.

[Plug] My project, NExtension contains AtLeast, AtMost and overrides that allow you to mix into a predicate with AtLeast / Big check. [/ Plug]

+2
Dec 19 '08 at 15:08
source share

Casting to ints and summing should work, but it's a little ugly and in some languages ​​it may not be possible.

How about something like

 int count = (bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0); 

Or, if you care about space, you can simply precompute the truth table and use bools as indices:

 if (morethanone[bool1][bool2][bool3][bool4][bool5]) { ... do something ... } 
+1
Dec 18 '08 at 14:43
source share

I would do something like this using the params argument.

  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; } 
+1
Dec 18 '08 at 14:48
source share

Not quite pretty ... but here is another way to do this:

 if ( (a && (b || c || d || e)) || (b && (c || d || e)) || (c && (d || e)) || (d && e) ) 
+1
Dec 18 '08 at 14:48
source share
 if (NumberOfTrue(new List<bool> { bool1, bool2, bool3, bool4 }) >= 2) { // do stuff } int NumberOfTrue(IEnumerable<bool> bools) { return bools.Count(b => b); } 
+1
Dec 18 '08 at 15:04
source share

I have now much better and very short!

 bool[] bools = { b1, b2, b3, b4, b5 }; if (bools.Where(x => x).Count() > 1) { //do stuff } 
+1
Dec 18 '08 at 15:34
source share

In most languages, true is equivalent to a nonzero value, and false is zero. I don't have the exact syntax for you, but in pseudocode, how about:

 if ((bool1 * 1) + (bool2 * 1) + (bool3 * 1) > 2) { //statements here } 
0
Dec 18 '08 at 14:36
source share

if ((b1.CompareTo (false) + b2.CompareTo (false) + b3.CompareTo (false) + ...)> 1)

// More than one of them is true

...

yet

...

0
Dec 18 '08 at 18:19
source share

If you have only five different values, you can easily run the test by packing the bits into short or int and checking if it is any of the answers to zero or one bit. The only invalid numbers you could get would be.

 0x 0000 0000 
 0x 0000 0001
 0x 0000 0010
 0x 0000 0100
 0x 0000 1000
 0x 0001 0000

This gives you six values ​​for the search, puts them in the search table, and if it is not there, you have your answer.

This gives you a simple answer.

    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, 0, 0, 0,
             1,0,0,0,0,0,0,0,0,0
             0, 0, 0, 0, 0, 0, 0, 0
       };
       if (multiBitLookup [b] == 1)
          return false;
       return true;
    }

It does not scale long to 8 bits, but you only have five.

0
Dec 18 '08 at 18:59
source share

You mentioned

One interesting option is to store Boolean in bytes, perform a right shift and compare with the original byte. Something like if (myByte && (myByte >> 1))

I don't think this expression will give you the result you want (at least using C semantics, since the expression is not valid C #):

If (myByte == 0x08) , then the expression will return true, even if only one bit is set.

If you meant " if (myByte & (myByte >> 1)) ", then if (myByte == 0x0a) expression will return false, even if 2 bits are set.

But here are a few methods for counting the number of bits in a word:

Twiddling Hacks Bit - Counting Bits

An option you might consider is to use the Kernighan counting method, but release it sooner since you only need to know if more than one bit is set:

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

Of course, using a lookup table is not a bad option.

0
Dec 19 '08 at 2:20
source share

I wanted to give an answer to the template version of 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; } 

simply calling it as follows creates a rather elegant method for counting the number of bools.

 if ( countBool( bool1, bool2, bool3 ) > 1 ) { .... } 
0
Jun 10 '17 at 20:30
source share

I recently had the same problem when I had three Boolean values, and I needed to check that only one of them was true at a time. For this, I used the xor operator as follows:

 bool a = true; bool b = true; bool c = false; if (a || b || c) { if (a ^ b ^ c){ //Throw Error } } 

This code throws an error since a and b are true.

For reference: http://www.dotnetperls.com/xor

I just found the xor operator in C #, if anyone knows about any crashes of this strategy, please let me know.

-one
Dec 24 '13 at 19:26
source share



All Articles