Frage

Ich habe eine Reihe von fünf Boolesche Werte. Wenn mehr als eine davon wahr sind möchte ich eine bestimmte Funktion excecute. Was ist die eleganteste Art und Weise Sie das erlauben würde denken kann mir diese Bedingung in einem einzigen if () Aussage zu überprüfen? Zielsprache ist C #, aber ich habe Interesse an Lösungen in anderen Sprachen als auch (solange wir nicht über bestimmte integrierte Funktionen im Gespräch).

Eine interessante Option ist die Boolesche Werte in einem Byte zu speichern, eine Rechtsverschiebung tun und mit dem ursprünglichen Byte zu vergleichen. So etwas wie if(myByte && (myByte >> 1)) Dies würde aber erfordern die einzelnen booleans auf ein Byte Umwandlung (über einen BitArray?) Und das scheint ein wenig (pun intended) ungeschickt ... [Bearbeiten] Sorry, das sollte gewesen sein if(myByte & (myByte - 1)) [/ edit]

Hinweis: Dies ist natürlich sehr nahe an die klassischen „Bevölkerungszahl“, „seitlich Zusatz“ oder „Hamming-Gewicht“ Programmierproblem - aber nicht ganz dasselbe. Ich brauche nicht zu wissen, wie viele der Bits gesetzt, nur wenn es mehr ist als eins. Meine Hoffnung ist, dass es eine viel einfachere Art und Weise, dies zu erreichen.

War es hilfreich?

Lösung

Wie wäre es

  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 mit LINQ wie von anderen Antworten vorgeschlagen:

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

EDIT (Joel Coehoorn Vorschlag hinzu: (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 IEnumerable<bool>

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

Nutzung wäre dann:

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

Andere Tipps

Ich wollte die Linq-Version schreiben, aber fünf oder so Leute schlugen mich darauf. Aber ich wie der params Ansatz wirklich zu vermeiden, manuell neu ein Array auf. Also ich denke, die beste Hybrid, bezogen auf rp Antwort mit dem Körper ersetzen mit dem offensichtlichen Linqness:

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)

Es ist Zeit für die obligatorische Antwort LINQ, die in diesem Fall eigentlich recht ordentlich ist.

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

return bools.Count(b => b == true) > 1;

Ich würde warf sie nur ints und Summe.

Wenn Sie in einer super engen inneren Schleife sind, dass hat den Vorteil, dass sie leicht zu verstehen.

Ich würde eine Funktion schreiben, eine beliebige Anzahl von Boolesche Werte zu erhalten. Es würde die Anzahl dieser Werte zurück, die wahr sind. Überprüfen Sie das Ergebnis für die Anzahl der Werte, die Sie brauchen, um etwas Positives zu tun.

Die Arbeit schwieriger wird es klar zu machen, nicht clever!

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

    return result;
}

Wenn Sie mehr bedeuten als oder gleich einem boolean true entspricht, man könnte es tun, wie

if (bool1 || bool2 || bool3 || bool4 || bool5)

Wenn Sie mehr als ein (2 und höher) booleans gleich wahr ist, können Sie 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

Wenn es Millionen statt nur 5 waren Sie Count vermeiden konnte () und geben Sie stattdessen ...

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

von der Oberseite meines Kopfes, einen schnellen Ansatz für dieses spezielle Beispiel; Sie konnte den Bool in einen int (0 oder 1) konvertieren. dann Schleife durch therm und fügen Sie sie auf. wenn das Ergebnis> = 2, dann können Sie Ihre Funktion ausführen.

Casting zu ints und Summieren arbeiten soll, aber es ist ein bisschen hässlich und in einigen Sprachen nicht möglich sein.

Wie wäre es so etwas wie

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

Oder wenn Sie nicht über den Raum kümmern, könnten Sie precompute nur die Wahrheitstabelle und verwenden Sie die bools als Indizes:

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

Ich würde so etwas tun, das params Argument verwendet wird.

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

Nicht gerade recht ... aber hier ist eine andere Art und Weise, es zu tun:

if (
    (a && (b || c || d || e)) ||
    (b && (c || d || e)) ||
    (c && (d || e)) ||
    (d && e)
)

Ich habe ein viel viel besser man jetzt und sehr kurz!

bool[] bools = { b1, b2, b3, b4, b5 };
if (bools.Where(x => x).Count() > 1)
{
   //do stuff
}

ich eine C ++ 11 variadische Vorlage Antwort geben wollte.

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

nennt es einfach wie folgt erzeugt eine eher elegante Methode, die Anzahl der bools zu zählen.

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

In den meisten Sprachen wahr entspricht einem Wert ungleich Null, während falsch Null ist. Ich habe keine genaue Syntax für Sie, aber in Pseudo-Code, was ist:

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

Wenn Sie nur fünf verschiedene Werte haben, können Sie leicht den Test durchführen, indem die Bits in zu kurzer Verpackung oder ein int und zu überprüfen, ob es eine der Null oder ein Bit Antworten ist. Die einzigen ungültigen Zahlen könnten Sie bekommen würde ..

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

Dies gibt Ihnen sechs Werte zu suchen, sie in einer Lookup-Tabelle setzen und wenn es dort nicht ist, haben Sie Ihre Antwort.

Dies gibt Ihnen eine einfache Antwort.

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

Diese skaliert nicht gut letzten 8 Bits, aber nur fünf haben.

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

// Mehr als einer von ihnen wahr ist

...

sonst

...

Sie haben erwähnt,

  

Eine interessante Option ist die Boolesche Werte in einem Byte zu speichern,   tun, um eine Verschiebung nach rechts und vergleichen Sie mit dem ursprünglichen Byte.   So etwas wie if (myByte && (myByte >> 1))

Ich glaube nicht, dass die Expression werden Sie das gewünschte Ergebnis (zumindest unter Verwendung von C-Semantik, da der Ausdruck nicht gültig C #):

Wenn (myByte == 0x08), dann wird der Ausdruck true zurück, obwohl es Satz nur ein Bit ist.

Wenn Sie bedeuten „if (myByte & (myByte >> 1))“ dann, wenn (myByte == 0x0a) des Ausdruck falsch zurück, obwohl es zwei Bits gesetzt.

Aber hier sind einige Techniken, um die Anzahl von Bits in einem Wort zu zählen:

Bit Twiddling Hacks - Zählen Bits

Eine Variation Sie betrachten könnte, ist Kernighan die Zählmethode zu verwenden, aber bail früh aus, da Sie nur wissen müssen, wenn es 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 eine Lookup-Tabelle mit keiner schlechten Option auch nicht.

Ich habe vor kurzem das gleiche Problem, wo ich drei Boolesche Werte hatte, die ich überprüfen musste, dass nur 1 von ihnen zu einer Zeit, war wahr. Dazu habe ich den XOR-Operator wie folgt:

bool a = true;
bool b = true;
bool c = false;

if (a || b || c)
{
    if (a ^ b ^ c){
        //Throw Error
    }
}

Dieser Code wird einen Fehler aus, als a und b beide wahr sind.

Referenz: http://www.dotnetperls.com/xor

Ich habe gerade erst den XOR-Operator in C # gefunden, wenn jemand weiß jede Grube dieser Strategie fällt, lassen Sie es mich wissen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top