둘 이상의 부울이 "참"인지 정중하게 결정
5 개의 부울 값 세트가 있습니다. 이 중 하나 이상이 사실이라면 특정 기능을 실행하고 싶습니다. 단일 if () 문에서이 조건을 확인할 수있는 가장 우아한 방법은 무엇입니까? 대상 언어는 C #이지만 다른 언어의 솔루션에도 관심이 있습니다 (특정 기본 제공 함수에 대해 이야기하지 않는 한).
한 가지 흥미로운 옵션은 부울을 바이트에 저장하고 오른쪽 시프트를 수행하고 원래 바이트와 비교하는 것입니다. 같은 뭔가 if(myByte && (myByte >> 1))
하지만이 (A 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; }
편집 (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와 sum으로 캐스팅 할 것입니다.
내부 루프가 매우 빡빡하지 않으면 이해하기 쉽다는 이점이 있습니다.
여러 부울 값을받는 함수를 작성합니다. 참인 값의 수를 반환합니다. 어떤 일을하기 위해 긍정적이어야하는 값의 수에 대한 결과를 확인하십시오.
명확하게하기 위해 더 열심히 노력하세요.
private int CountTrues( params bool[] booleans )
{
int result = 0;
foreach ( bool b in booleans )
{
if ( b ) result++;
}
return result;
}
하나 이상의 부울이 true와 같거나 같음을 의미하면 다음과 같이 할 수 있습니다.
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);
}
플래그가 한 단어로 압축되면 Michael Burr의 솔루션 이 작동합니다. 그러나 루프는 필요하지 않습니다.
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를 좋아하지만이 문제와 같은 몇 가지 구멍이 있습니다.
일반적으로 개수를 계산하는 것은 좋지만 항목을 계산 / 검색하는 데 시간이 걸리는 경우 문제가 될 수 있습니다.
Any () 확장 메서드는 어떤 것을 확인하고 싶다면 괜찮지 만 적어도 확인하고 싶다면 그것을 수행하고 게 으르는 내장 함수가 없습니다.
결국, 목록에 항목이 특정 개수 이상 있으면 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 / Most 검사와 술어를 혼합 할 수있는 재정의가 포함되어 있습니다. [/플러그]
int로 캐스트하고 합산하면 작동하지만 약간 추하고 일부 언어에서는 불가능할 수 있습니다.
같은 건 어때
int count = (bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0);
또는 공간에 관심이 없다면 진리표를 미리 계산하고 bool을 인덱스로 사용할 수 있습니다.
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;
}
simply calling it as follows creates a rather elegant method of counting the number of bools.
if ( countBool( bool1, bool2, bool3 ) > 1 )
{
....
}
In most languages true is equivalent to a non-zero value while false is zero. I don't have exact syntax for you, but in pseudo code, what about:
if ((bool1 * 1) + (bool2 * 1) + (bool3 * 1) > 2)
{
//statements here
}
If you only have five different values, you can easily do the test by packing the bits in to a short or an int and checking to see if it is any of the zero or one bit answers. 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 to search for, put them in a lookup table and if it's not in 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, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if(multiBitLookup[b] == 1) return false; return true; }
This doesn't scale well past 8 bits, but you only have five.
if((b1.CompareTo( false ) + b2.CompareTo( false ) + b3.CompareTo( false ) + ...) > 1)
// More than one of them are true
...
else
...
You mentioned
One interesting option is to store the booleans in a byte, do a right shift and compare with the original byte. Something like
if (myByte && (myByte >> 1))
I don't think that 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 though there's only one bit set.
If you meant "if (myByte & (myByte >> 1))
" then if (myByte == 0x0a)
the expression will return false even though there are 2 bits set.
But here are some techniques for counting the number of bits in a word:
Bit Twiddling Hacks - Counting bits
A variation you might consider is to use Kernighan's counting method, but bail out early since you only need to know if there's more than one bit 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's not a bad option either.
I was recently having this same issue, where I had three boolean values, which I needed to check that only 1 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 will throw an error as a and b are both true.
For reference: http://www.dotnetperls.com/xor
I have only just found the xor operator in C# if anyone knows of any pit falls of this strategy, please let me know.
참고URL : https://stackoverflow.com/questions/377990/elegantly-determine-if-more-than-one-boolean-is-true
'Program Tip' 카테고리의 다른 글
사용자가 컨트롤러 내부에서 Symfony2에 로그인했는지 확인하는 방법은 무엇입니까? (0) | 2020.10.22 |
---|---|
숭고한 텍스트 2에서 명령 모드 종료 (0) | 2020.10.22 |
Rails 컨트롤러에서 도우미 메서드를 호출하려고 할 때 NoMethodError (0) | 2020.10.22 |
문자열 내에서 변수 사용 (0) | 2020.10.22 |
CollectionView sizeForItemAtIndexPath가 호출되지 않았습니다. (0) | 2020.10.22 |