我有一组五个布尔的价值观。如果一个以上的这些都是真的我想要执行特定功能。什么是最优雅的方式可以认为这会允许我检查这种情况在单一,如果()发言?目标语言是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; }

编辑(添加乔尔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的版本,但五年左右的人打我给它。但我真的很喜欢PARAMS方法来避免手动新兴起来的一个数组。因此,我认为最好的混合动力,基于RP的与身体的答案具有明显的Linqness替换:

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;

我只是它们转换成整数和总和。

除非你在一个超级紧内循环的时候,具有的易于理解的好处。

我会写一个功能,以接收任何数量的布尔值的。它会返回那些真值的数量。检查结果为值的数量你需要积极做一些事情。

工作更难说清楚,不聪明!

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

如果你的标志是打包成一个单词然后 迈克尔*伯尔解决方案 将工作。但是,循环不必要的:

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,则可以执行的功能。

虽然我喜欢LINQ,有在它的一些孔,像这样的问题。

做一个计数一般正常,但可以成为一个问题,当你的项目计数需要一段时间来计算/检索。

在任何()扩展方法是好的,如果你只是想检查是否有,但如果你想检查至少没有内置的功能,将做到这一点,是懒惰的。

在最后,我写了一个函数,如果有至少列表中的项目的特定数量的返回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 包含ATLEAST,AtMost和覆盖,让您在混谓语与ATLEAST /大多数检查。 [/插头]

铸造到整数和总结应该工作,但它是一个有点难看,而且在某些语言可能是不可能的。

如何像

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

或者,如果你不关心的空间,你可以只预先计算的真值表,并使用布尔变量作为指标:

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

简单地调用其如下产生计数的bool的数目的相当优雅方法。

if ( countBool( bool1, bool2, bool3 ) > 1 )
{
  ....
}

在大多数语言真相当于一个非零值,而假是零。我没有确切的语法对你,但在伪代码,怎么样:

if ((bool1 * 1) + (bool2 * 1) + (bool3 * 1) > 2)
{
    //statements here
}

如果你只有五个不同的值,可以很容易地通过在一个短的或int包装比特和检查,看它是否是任何的零个或一个比特的答案做了测试。唯一的无效数字,你可以得到会..

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

这给你六个值来搜索,把它们放在一个查找表,如果它不是在那里,你有你的答案。

这给你一个简单的答案。

   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位很好地扩展,但你只有五位。

如果((b1.CompareTo(假)+ b2.CompareTo(假)+ b3.CompareTo(假)+ ...)> 1)

//超过它们中的一个为真

...

否则

...

您提到

  

一个有趣的选择是将布尔值存储在一个字节,   做右移并与原始字节进行比较。   像if (myByte && (myByte >> 1))

我不认为表达会给你你想要的结果(至少用C语义,因为表达式是无效的C#):

如果(myByte == 0x08),则表达式将即使只有一个位集返回true。

如果你的意思是“if (myByte & (myByte >> 1))”那么,如果(myByte == 0x0a)表达式将返回即使有设置2位错误的。

但在这里是用于在字计数位的数目的一些技术:

位操作黑客 - 计数位

你可能会考虑一个变化是使用Kernighan的的计数方法,但保释出来早,因为你只需要知道,如果有一个以上的位设置:

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个是真正的在同一时间。为此,我使用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运算,如果有人知道的任何坑属于这一战略的,请让我知道。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top