Question

J'ai un ensemble de cinq valeurs booléennes. Si plus d'un d'entre eux sont vraies, je veux Excecute une fonction particulière. Quelle est la façon la plus élégante que vous pouvez penser qui me permettrait de vérifier cette condition dans un état unique si ()? Langue cible est C #, mais je suis intéressé par des solutions dans d'autres langues (aussi longtemps que nous ne parlons pas de fonctions intégrées spécifiques).

Une option intéressante est de stocker les booléens dans un octet, faire un décalage vers la droite et la comparer avec l'octet d'origine. Quelque chose comme if(myByte && (myByte >> 1)) Mais cela nécessiterait la conversion des booléens séparés à un octet (via un BitArray?) Et qui semble un peu (jeu de mots) maladroit ... [modifier] Désolé, cela aurait dû être if(myByte & (myByte - 1)) [/ edit]

Note: Ceci est bien sûr très proche du « nombre de la population » classique « sur le côté plus » ou d'un problème de programmation « poids Hamming » - mais pas tout à fait la même chose. Je ne ai pas besoin de savoir combien de bits sont, que si elle est plus d'un. Mon espoir est qu'il ya une manière beaucoup plus simple d'y arriver.

Était-ce utile?

La solution

Qu'en est-

  if ((bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + 
      (bool4? 1:0) + (bool5? 1:0) > 1)
      // do something

ou une méthode généralisée serait ...

   public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
    {
       int trueCnt = 0;
       foreach(bool b in bools)
          if (b && (++trueCnt > threshold)) 
              return true;
       return false;          
    } 

ou en utilisant LINQ comme suggéré par d'autres réponses:

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

EDIT (pour ajouter la suggestion Joel Coehoorn: (Dans 2.x Net et versions ultérieures)

    public void ExceedsThreshold<T>(int threshold, 
                      Action<T> action, T parameter, 
                      IEnumerable<bool> bools)
    { if (ExceedsThreshold(threshold, bools)) action(parameter); }

ou .Net 3.5 et versions ultérieures:

    public void ExceedsThreshold(int threshold, 
            Action action, IEnumerable<bool> bools)
    { if (ExceedsThreshold(threshold, bools)) action(); }

ou comme une extension de IEnumerable<bool>

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

utilisation serait alors:

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

Autres conseils

J'allais écrire la version LINQ, mais cinq ou six personnes me devança. Mais je vraiment l'approche params pour éviter de devoir manuellement nouveau jusqu'à un tableau. Je pense donc que le meilleur hybride est basé sur la réponse de rp avec le corps remplacer par la Linqness évidente:

public static int Truth(params bool[] booleans)
{
    return booleans.Count(b => b);
}

Magnifiquement clair à lire et à utiliser:

if (Truth(m, n, o, p, q) > 2)

Il est temps pour la réponse LINQ obligatoire, qui dans ce cas est en réalité tout à fait propre.

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

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

Je voudrais juste les jeter à ints et somme.

Sauf si vous êtes dans une boucle intérieure super serré, qui a l'avantage d'être facile à comprendre.

J'écrire une fonction pour recevoir un certain nombre de valeurs booléennes. Il retourne le nombre de ces valeurs qui sont vraies. Vérifiez le résultat pour le nombre de valeurs que vous devez être positif pour faire quelque chose.

Travailler plus dur pour le rendre clair, pas intelligent!

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

    return result;
}

si vous voulez dire plus ou égale à un booléen vaut true, vous pouvez le faire comme

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

Si vous avez besoin de plus d'un (2 et plus) égale booléens true, vous pouvez essayer

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

S'il y avait des millions au lieu de seulement 5, vous pouvez éviter le comte () et faire la place ...

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

du haut de ma tête, une approche rapide pour cet exemple spécifique; vous pouvez convertir le bool à un int (0 ou 1). puis boucle à travers therm et les additionner. si le résultat> = 2 alors vous pouvez exécuter votre fonction.

Castings à ints et la somme devrait fonctionner, mais il est un peu moche et dans certaines langues peuvent ne pas être possible.

Que diriez-vous quelque chose comme

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

Ou si vous ne se soucient pas de l'espace, vous pouvez simplement précalculer la table de vérité et d'utiliser les bools comme indices:

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

Je ferais quelque chose comme cela, en utilisant l'argument 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);
}

Pas exactement assez ... mais voici une autre façon de le faire:

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

J'ai beaucoup mieux maintenant et un très court!

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

Je voulais donner une réponse modèle variadique 11 C ++.

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

appelant simplement comme suit crée une méthode assez élégante de compter le nombre de bools.

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

Dans la plupart des vraies langues est équivalente à une valeur non nulle en faux est égal à zéro. Je n'ai pas la syntaxe exacte pour vous, mais dans le code pseudo, qu'en est:

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

Si vous avez seulement cinq valeurs différentes, vous pouvez facilement faire le test en emballant les bits pour un court ou un int et vérifier pour voir si elle est l'un des zéro ou une réponse de bit. Les seuls numéros invalides que vous pourriez obtenir serait ..

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

Cela vous donne six valeurs pour la recherche, les mettre dans une table de consultation et si ce n'est pas là-dedans, vous avez votre réponse.

Cela vous donne une réponse simple.

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

Cela n'échelle pas bien passé 8 bits, mais vous ne disposez que de cinq.

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

// Plus d'un d'entre eux sont vraies

...

autre

...

Vous avez mentionné

  

Une option intéressante est de stocker les booléens dans un octet,   faire un décalage vers la droite et la comparer avec l'octet d'origine.   Quelque chose comme if (myByte && (myByte >> 1))

Je ne pense pas que l'expression vous donnera le résultat que vous voulez (au moins en utilisant la sémantique C, puisque l'expression est pas valide C #):

Si (myByte == 0x08), l'expression retourne vrai même si il n'y a qu'un seul bit.

Si vous vouliez dire « if (myByte & (myByte >> 1)) » alors si (myByte == 0x0a) l'expression retourne faux, même si il y a 2 bits définis.

Mais voici quelques techniques pour compter le nombre de bits en un mot:

Bit twiddling Hacks - bits de comptage

Une variante possible consiste à utiliser la méthode de comptage de Kernighan, mais une caution tôt puisque vous ne devez savoir s'il y a plus d'un bit:

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

Bien sûr, à l'aide d'une table de recherche n'est pas une mauvaise option non plus.

J'ai été récemment avoir cette même question, où j'ai eu trois valeurs booléennes, dont je avais besoin pour vérifier que seulement 1 d'entre eux était vrai à la fois. Pour cela je l'opérateur XOR comme suit:

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

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

Ce code renvoie une erreur comme et b sont vraies.

Pour référence: http://www.dotnetperls.com/xor

Je n'ai juste trouvé l'opérateur XOR en C # si quelqu'un sait de toute fosse tombe de cette stratégie, s'il vous plaît laissez-moi savoir.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top