优雅地确定多个布尔值是否为"true"

Ola*_*son 73 c# hammingweight

我有一组五个布尔值.如果其中不止一个是真的,我想要执行特定的功能.您能想到的最优雅的方法是什么,这样我才能在单个if()语句中检查这种情况?目标语言是C#,但我也对其他语言的解决方案感兴趣(只要我们不讨论特定的内置函数).

一个有趣的选择是将布尔值存储在一个字节中,进行右移并与原始字节进行比较.类似if(myByte && (myByte >> 1))但是这需要将单独的布尔值转换为一个字节(通过bitArray?),这似乎有点(双关语)笨拙... [编辑]对不起,应该是 if(myByte & (myByte - 1)) [/ edit]

注意:这当然非常接近经典的"人口数量","横向增加"或"汉明重量"编程问题 - 但不完全相同.我不需要知道有多少位被设置,只要它不止一个.我希望有一种更简单的方法来实现这一目标.

Dan*_*ker 115

我打算写Linq版本,但是有五个人打败了我.但我真的很喜欢params方法,以避免手动新建数组.所以我认为最好的混合动力是,基于rp的回答与身体取代明显的Linqness:

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

非常清楚阅读和使用:

if (Truth(m, n, o, p, q) > 2)
Run Code Online (Sandbox Code Playgroud)


Cha*_*ana 85

怎么样

  if ((bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + 
      (bool4? 1:0) + (bool5? 1:0) > 1)
      // do something
Run Code Online (Sandbox Code Playgroud)

或者一般化的方法是......

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

或者使用其他答案建议的LINQ:

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

编辑(添加Joel Coehoorn的建议:(在.Net 2.x及更高版本中)

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

或.Net 3.5及更高版本:

    public void ExceedsThreshold(int threshold, 
            Action action, IEnumerable<bool> bools)
    { if (ExceedsThreshold(threshold, bools)) action(); }
Run Code Online (Sandbox Code Playgroud)

或作为...的延伸 IEnumerable<bool>

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

用法将是:

  var bools = new [] {true, true, false, false, false, false, true};
  if (bools.ExceedsThreshold(3))
      // code to execute  ...
Run Code Online (Sandbox Code Playgroud)

  • 建议 - 一旦b>阈值,就打破循环. (2认同)

Gar*_*ler 18

现在是强制性LINQ答案的时候了,在这种情况下实际上非常简洁.

var bools = new[] { true, true, false, false, false };

return bools.Count(b => b == true) > 1;
Run Code Online (Sandbox Code Playgroud)

  • 或者只是计数(b => b) (7认同)

rec*_*ive 16

我会把它们投入到整数和总和中.

除非你处于一个超紧密的内循环中,否则它具有易于理解的优点.

  • 有人必须添加这个的linq版本:myBools.Cast <int>().Sum()! (2认同)
  • @Jennifer有点晚了(!)但遗憾的是`Cast <int>().Sum()`会在一系列bool上抛出异常.虽然你可以强制转换`bool` - >`int`,你不能强制转换`bool` - >`object` - >`int`,这就是幕后发生的事情. (2认同)

rp.*_*rp. 6

我写了一个函数来接收任意数量的布尔值.它将返回那些值为true的值.检查结果是否需要积极的值来执行某些操作.

更加努力地说清楚,而不是聪明!

private int CountTrues( params bool[] booleans )
{
    int result = 0;
    foreach ( bool b in booleans )
    {
        if ( b ) result++;
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)


fau*_*lty 5

如果您的意思是大于或等于一个布尔值等于true,则可以这样做

if (bool1 || bool2 || bool3 || bool4 || bool5)
Run Code Online (Sandbox Code Playgroud)

如果您需要多个(等于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
Run Code Online (Sandbox Code Playgroud)


Ian*_*cer 5

如果有数百万而不是只有5,你可以避免Count()而是这样做......

public static bool MoreThanOne (IEnumerable<bool> booleans)
{
    return booleans.SkipWhile(b => !b).Skip(1).Any(b => b);
}
Run Code Online (Sandbox Code Playgroud)

  • 建议更简洁的版本: `return booleans.Where(b =&gt; b).Skip(1).Any()` 这也适用于我们想知道是否有超过 N 个成员满足某些条件的任何情况。 (2认同)

fin*_*nnw 5

如果你的旗帜被打包成一个单词,那么Michael Burr的解决方案就可以了.但是,循环不是必需的:

int moreThanOneBitSet( unsigned int v)
{
    return (v & (v - 1)) != 0;
}
Run Code Online (Sandbox Code Playgroud)

 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
Run Code Online (Sandbox Code Playgroud)