하나 이상의 부울이“진실”인지 우아하게 결정하십시오.

StackOverflow https://stackoverflow.com/questions/377990

  •  22-08-2019
  •  | 
  •  

문제

5 개의 부울 값이 있습니다. 이 중 하나 이상이 사실이라면 특정 기능을 발굴하고 싶습니다. 단일 if () 문서 에서이 조건을 확인할 수있는 가장 우아한 방법은 무엇입니까? 대상 언어는 C#이지만 다른 언어의 솔루션에도 관심이 있습니다 (특정 내장 기능에 대해 이야기하지 않는 한).

흥미로운 옵션 중 하나는 부울을 바이트에 보관하고 올바른 교대를하고 원래 바이트와 비교하는 것입니다. 같은 것 if(myByte && (myByte >> 1)) 그러나 이것은 별도의 부울을 바이트 (비트 array를 통해?)로 변환해야하며 약간 (말장난 의도) 서투른 것 같습니다 ... 편집] 죄송합니다 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; }

편집 (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); }

또는 .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 버전을 작성하려고했지만 5 명 정도의 사람들이 저를 이겼습니다. 그러나 나는 배열을 수동으로 새로 새로워지는 것을 피하기 위해 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;

나는 단지 그들을 INT와 합으로 던질 것입니다.

당신이 매우 타이트한 내부 루프에 있지 않으면 이해하기 쉬운 이점이 있습니다.

부울 값을 여러 번 받기 위해 함수를 작성했습니다. 사실 인 값의 수를 반환합니다. 무언가를하기 위해 긍정적이어야하는 값의 수를 결과를 확인하십시오.

영리하지 않고 명확하게하기 위해 더 열심히 노력하십시오!

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)

True와 동일한 2 개 이상의 부울이 필요한 경우 시도 할 수 있습니다.

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 대신 수백만 명이 있으면 count ()를 피하고 대신 이것을 할 수 있습니다 ...

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

내 머리 꼭대기 에서이 특정 예에 대한 빠른 접근 방식; bool을 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);

결과를 반환하기 전에 모든 항목을 평가할 필요가 없다는 이점이 있습니다.

플러그] 내 프로젝트, 발신 적어도, 최대 및 재정의를 포함하여 술어를 적어도/대부분의 수표와 혼합 할 수 있습니다. [/플러그

ints에 캐스팅하고 합산하는 것이 효과가 있어야하지만 약간 추악하고 일부 언어로는 불가능할 수 있습니다.

어떤 것 같아요

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

또는 공간을 신경 쓰지 않으면 진실 테이블을 사전 컴퓨팅하고 Bools를 지수로 사용할 수 있습니다.

if (morethanone[bool1][bool2][bool3][bool4][bool5]) {
 ... do something ...
}

나는 매개 변수 인수를 사용하여 이와 같은 일을 할 것입니다.

        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 Variadic 템플릿 답변을주고 싶었습니다.

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

단순히 다음과 같이 부르는 것은 부울의 수를 세는 다소 우아한 방법을 만듭니다.

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

대부분의 언어에서 True는 0이 아닌 값과 동일하고 False는 0입니다. 나는 당신을위한 정확한 구문이 없지만 의사 코드에서는 다음과 같습니다.

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

다섯 가지 값 만있는 경우 비트를 짧은 또는 int로 포장하여 쉽게 테스트를 수행하고 0 또는 1 비트 답변인지 확인할 수 있습니다. 당신이 얻을 수있는 유일한 유효하지 않은 숫자는 ..

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

이것은 당신에게 검색 할 6 가지 값을 제공하고, 조회 테이블에 넣고, 거기에 있지 않으면, 당신은 당신의 대답을 할 수 있습니다.

이것은 당신에게 간단한 대답을 제공합니다.

   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 비트를 넘어서는 것이 좋지 않지만 5 개만 있습니다.

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

// 그들 중 하나 이상이 사실입니다

...

또 다른

...

당신은 언급했습니다

흥미로운 옵션 중 하나는 부울을 바이트에 보관하고 올바른 교대를하고 원래 바이트와 비교하는 것입니다. 같은 것 if (myByte && (myByte >> 1))

표현식은 당신이 원하는 결과를 줄 것이라고 생각하지 않습니다 (표현이 유효하지 않기 때문에 C 시맨틱을 사용합니다) :

만약에 (myByte == 0x08), 비트 세트가 하나만 있더라도 표현식은 사실이 반환됩니다.

당신이 의미한다면 "if (myByte & (myByte >> 1))"그럼 (myByte == 0x0a) 2 비트 세트가 있어도 표현식이 거짓으로 반환됩니다.

그러나 다음은 한 단어의 비트 수를 계산하는 몇 가지 기술입니다.

비트 twiddling 해킹 - 비트 계산

당신이 고려할 수있는 변형은 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);
}

물론 조회 테이블을 사용하는 것은 나쁜 옵션도 아닙니다.

나는 최근에 같은 문제를 겪고 있었는데, 나는 세 가지 부울 값을 가지고 있었는데, 그중 하나만이 한 번에 사실인지 확인해야했습니다. 이를 위해 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