Ich habe einen Satz von fünf booleschen Werten. Wenn mehr als eine davon wahr ist, möchte ich eine bestimmte Funktion ausführen. Was ist die eleganteste Art, wie Sie sich das vorstellen können, um diese Bedingung in einer einzigen if () - Anweisung zu überprüfen? Die Zielsprache ist C #, aber ich bin auch an Lösungen in anderen Sprachen interessiert (solange es sich nicht um bestimmte integrierte Funktionen handelt).
Eine interessante Option besteht darin, die Booleschen Werte in einem Byte zu speichern, eine Rechtsverschiebung durchzuführen und mit dem ursprünglichen Byte zu vergleichen. So etwas wie if(myByte && (myByte >> 1))
Aber dies würde die Konvertierung der separaten Booleschen Werte in ein Byte erfordern (über ein BitArray?) Und das scheint ein bisschen (Wortspiel beabsichtigt) ungeschickt zu sein ... [Bearbeiten] Entschuldigung, das hätte sein sollen if(myByte & (myByte - 1))
[/ Bearbeiten]
Hinweis: Dies kommt natürlich dem klassischen Programmierproblem "Bevölkerungszahl", "Seitwärtsaddition" oder "Hamming-Gewicht" sehr nahe - ist aber nicht ganz dasselbe. Ich muss nicht wissen, wie viele der Bits gesetzt sind, nur wenn es mehr als eins sind. Ich hoffe, dass es einen viel einfacheren Weg gibt, dies zu erreichen.
quelle
Antworten:
Wie wäre es mit
if ((bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0) > 1) // do something
oder eine verallgemeinerte Methode wäre ...
public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools) { int trueCnt = 0; foreach(bool b in bools) if (b && (++trueCnt > threshold)) return true; return false; }
oder Verwenden von LINQ, wie in anderen Antworten vorgeschlagen:
public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools) { return bools.Count(b => b) > threshold; }
BEARBEITEN (um Joel Coehoorns Vorschlag hinzuzufügen: (in .Net 2.x und höher)
public void ExceedsThreshold<T>(int threshold, Action<T> action, T parameter, IEnumerable<bool> bools) { if (ExceedsThreshold(threshold, bools)) action(parameter); }
oder in .Net 3.5 und höher:
public void ExceedsThreshold(int threshold, Action action, IEnumerable<bool> bools) { if (ExceedsThreshold(threshold, bools)) action(); }
oder als Erweiterung zu
IEnumerable<bool>
public static class IEnumerableExtensions { public static bool ExceedsThreshold<T> (this IEnumerable<bool> bools, int threshold) { return bools.Count(b => b) > threshold; } }
Verwendung wäre dann:
var bools = new [] {true, true, false, false, false, false, true}; if (bools.ExceedsThreshold(3)) // code to execute ...
quelle
Ich wollte die Linq-Version schreiben, aber ungefähr fünf Leute haben mich geschlagen. Aber ich mag den params-Ansatz sehr, um zu vermeiden, dass ein Array manuell neu erstellt werden muss. Ich denke also, der beste Hybrid ist, basierend auf der Antwort von rp, wobei der Körper durch die offensichtliche Linqness ersetzt wird:
public static int Truth(params bool[] booleans) { return booleans.Count(b => b); }
Schön klar zu lesen und zu verwenden:
if (Truth(m, n, o, p, q) > 2)
quelle
static int MatchCount<T>(Predicate<T> match, params T[] objs) { return objs.Count(obj => match(obj)); }
. Um die Anzahl der positiven Werte zu zählen:double a, b, c, d; ... MatchCount(x => x > 0.0, a, b, c, d);
Und so weiter ...new[] { a, b, c, d }.Count(x => x > 0.0)
Es ist Zeit für die obligatorische LINQ-Antwort, die in diesem Fall eigentlich ganz ordentlich ist.
var bools = new[] { true, true, false, false, false }; return bools.Count(b => b == true) > 1;
quelle
Ich würde sie nur in Ints und Summen umwandeln.
Wenn Sie sich nicht in einer sehr engen inneren Schleife befinden, hat dies den Vorteil, dass Sie leicht zu verstehen sind.
quelle
Cast<int>().Sum()
Wird aber leider eine Ausnahme auf eine Folge von Bools werfen. Obwohl Sie besetzen könnenbool
->int
, können Sie nicht besetzenbool
->object
->int
, was hier hinter den Kulissen passiert.Ich würde eine Funktion schreiben, um eine beliebige Anzahl von Booleschen Werten zu erhalten. Es würde die Anzahl der Werte zurückgeben, die wahr sind. Überprüfen Sie das Ergebnis auf die Anzahl der Werte, die Sie benötigen, um etwas zu tun.
Arbeite härter, um es klar zu machen, nicht klug!
private int CountTrues( params bool[] booleans ) { int result = 0; foreach ( bool b in booleans ) { if ( b ) result++; } return result; }
quelle
Wenn Sie meinen, dass mehr als oder gleich einem Booleschen Wert gleich wahr ist, können Sie es so machen
if (bool1 || bool2 || bool3 || bool4 || bool5)
Wenn Sie mehr als einen (2 und mehr) Booleschen Wert benötigen, der gleich true ist, können Sie es versuchen
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
quelle
Wenn es Millionen statt nur 5 gäbe, könnten Sie Count () vermeiden und dies stattdessen tun ...
public static bool MoreThanOne (IEnumerable<bool> booleans) { return booleans.SkipWhile(b => !b).Skip(1).Any(b => b); }
quelle
return booleans.Where(b => b).Skip(1).Any()
Dies gilt auch für alle Fälle, in denen wir wissen möchten, ob mehr als N Mitglieder eine bestimmte Bedingung erfüllen.Wenn Ihre Flaggen in einem Wort zusammengefasst sind, funktioniert die Lösung von Michael Burr . Die Schleife ist jedoch nicht erforderlich:
int moreThanOneBitSet( unsigned int v) { return (v & (v - 1)) != 0; }
Beispiel
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
quelle
Kürzer und hässlicher als die Vilx-Version:
if (((a||b||c)&&(d||e))||((a||d)&&(b||c||e))||(b&&c)) {}
quelle
von oben ein kurzer Ansatz für dieses spezielle Beispiel; Sie können den Bool in ein int (0 oder 1) konvertieren. dann durch therm schleifen und addieren. Wenn das Ergebnis> = 2 ist, können Sie Ihre Funktion ausführen.
quelle
Während ich LINQ mag, gibt es einige Löcher, wie dieses Problem.
Das Zählen ist im Allgemeinen in Ordnung, kann jedoch zu einem Problem werden, wenn das Berechnen / Abrufen der zu zählenden Elemente eine Weile dauert.
Die Any () - Erweiterungsmethode ist in Ordnung, wenn Sie nur nach einer suchen möchten, aber wenn Sie nach mindestens suchen möchten, gibt es keine eingebaute Funktion, die dies tut und faul ist.
Am Ende habe ich eine Funktion geschrieben, die true zurückgibt, wenn mindestens eine bestimmte Anzahl von Elementen in der Liste enthalten ist.
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; }
Benutzen:
var query = bools.Where(b => b).AtLeast(2);
Dies hat den Vorteil, dass nicht alle Elemente ausgewertet werden müssen, bevor ein Ergebnis zurückgegeben wird.
[Plug] Mein Projekt, NExtension, enthält AtLeast, AtMost und Überschreibungen, mit denen Sie das Prädikat mit dem AtLeast / Most-Check mischen können. [/Stecker]
quelle
Das Casting in Ints und Summieren sollte funktionieren, ist aber etwas hässlich und in einigen Sprachen möglicherweise nicht möglich.
Wie wäre es mit so etwas
int count = (bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0);
Oder wenn Sie sich nicht für Platz interessieren, können Sie einfach die Wahrheitstabelle vorberechnen und die Bools als Indizes verwenden:
if (morethanone[bool1][bool2][bool3][bool4][bool5]) { ... do something ... }
quelle
Ich würde so etwas mit dem Argument params machen.
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; }
quelle
if (NumberOfTrue(new List<bool> { bool1, bool2, bool3, bool4 }) >= 2) { // do stuff } int NumberOfTrue(IEnumerable<bool> bools) { return bools.Count(b => b); }
quelle
Nicht gerade hübsch ... aber hier ist eine andere Möglichkeit:
if ( (a && (b || c || d || e)) || (b && (c || d || e)) || (c && (d || e)) || (d && e) )
quelle
Ich habe jetzt eine viel viel bessere und sehr kurze!
bool[] bools = { b1, b2, b3, b4, b5 }; if (bools.Where(x => x).Count() > 1) { //do stuff }
quelle
Ich wollte eine Antwort auf eine variable C ++ 11-Vorlage geben.
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; }
Wenn Sie es einfach wie folgt aufrufen, erhalten Sie eine ziemlich elegante Methode zum Zählen der Anzahl der Bools.
if ( countBool( bool1, bool2, bool3 ) > 1 ) { .... }
quelle
In den meisten Sprachen entspricht true einem Wert ungleich Null, während false Null ist. Ich habe keine genaue Syntax für Sie, aber was ist mit Pseudocode?
if ((bool1 * 1) + (bool2 * 1) + (bool3 * 1) > 2) { //statements here }
quelle
Wenn Sie nur fünf verschiedene Werte haben, können Sie den Test einfach durchführen, indem Sie die Bits in ein kurzes oder ein int packen und prüfen, ob es sich um eine der Null- oder Ein-Bit-Antworten handelt. Die einzigen ungültigen Zahlen, die Sie bekommen könnten, wären ..
Auf diese Weise können Sie nach sechs Werten suchen, diese in eine Nachschlagetabelle einfügen und wenn sie nicht vorhanden sind, haben Sie Ihre Antwort.
Dies gibt Ihnen eine einfache Antwort.
Dies skaliert nicht weit über 8 Bit hinaus, aber Sie haben nur fünf.
quelle
if ((b1.CompareTo (false) + b2.CompareTo (false) + b3.CompareTo (false) + ...)> 1)
// Mehr als einer von ihnen ist wahr
...
sonst
...
quelle
Du erwähntest
Ich glaube nicht, dass dieser Ausdruck das gewünschte Ergebnis liefert (zumindest unter Verwendung der C-Semantik, da der Ausdruck in C # nicht gültig ist):
Wenn
(myByte == 0x08)
, dann gibt der Ausdruck true zurück, obwohl nur ein Bit gesetzt ist.Wenn Sie "
if (myByte & (myByte >> 1))
" gemeint haben, dann, wenn(myByte == 0x0a)
der Ausdruck false zurückgibt, obwohl 2 Bits gesetzt sind.Aber hier sind einige Techniken zum Zählen der Anzahl von Bits in einem Wort:
Bit Twiddling Hacks - Bits zählen
Eine Variante, die Sie in Betracht ziehen könnten, ist die Verwendung der Kernighan-Zählmethode. Sie können jedoch frühzeitig aussteigen, da Sie nur wissen müssen, ob mehr als ein Bit gesetzt ist:
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); }
Natürlich ist die Verwendung einer Nachschlagetabelle auch keine schlechte Option.
quelle
Ich hatte kürzlich das gleiche Problem, bei dem ich drei boolesche Werte hatte, mit denen ich überprüfen musste, ob jeweils nur einer wahr war. Dafür habe ich den xor-Operator wie folgt verwendet:
bool a = true; bool b = true; bool c = false; if (a || b || c) { if (a ^ b ^ c){ //Throw Error } }
Dieser Code gibt einen Fehler aus, da a und b beide wahr sind.
Als Referenz: http://www.dotnetperls.com/xor
Ich habe den xor-Operator gerade erst in C # gefunden. Wenn jemand von Grubenstürzen dieser Strategie weiß, lassen Sie es mich bitte wissen.
quelle