Pregunta

Tengo un conjunto de cinco valores booleanos. Si hay más de una de estas son verdaderas Quiero excecute una función particular. ¿Cuál es la forma más elegante se puede pensar en que me permitiera comprobar esta condición en una sola sentencia if ()? idioma de destino es C #, pero estoy interesado en soluciones en otros idiomas, así (con tal de que no estamos hablando de funciones incorporadas específicas).

Una opción interesante es almacenar los valores booleanos en un byte, hacer un desplazamiento a la derecha y comparar con el byte inicial. Algo así como if(myByte && (myByte >> 1)) Pero esto requeriría la conversión de los booleanos separados a un byte (a través de un BitArray?) Y que parece un poco (nunca mejor dicho) torpe ... [editar] Lo sentimos, que debería haber sido if(myByte & (myByte - 1)) [/ editar]

Nota: Esto es por supuesto muy cerca de la clásica "recuento de la población", "de lado adición" o problema de programación "peso Hamming" -, pero no es lo mismo. No necesito saber cuántos de los bits se establecen, sólo si es más de uno. Mi esperanza es que hay una manera mucho más sencilla de lograr esto.

¿Fue útil?

Solución

¿Qué tal

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

o un método generalizado sería ...

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

o el uso de LINQ según lo sugerido por otras respuestas:

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

Edit (para agregar Joel Coehoorn sugerencia: (En .Net 2.x y posterior)

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

o en .Net 3.5 y versiones posteriores:

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

o como una extensión de IEnumerable<bool>

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

uso sería entonces:

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

Otros consejos

Yo iba a escribir la versión de LINQ, pero cinco o más personas se me adelantó. Pero me gusta mucho el enfoque params para evitar tener que nueva manualmente una matriz. Así que creo que es el mejor híbrido, basado en la respuesta de RP con el cuerpo reemplace con la Linqness obvia:

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

Muy bien claro para leer y usar:

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

Es hora de que la respuesta obligatoria LINQ, que en este caso es en realidad bastante ordenada.

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

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

Yo sólo les echaría a enteros y suma.

A menos que estés en un bucle interno súper duro, que tiene la ventaja de ser fácil de entender.

Me gustaría escribir una función para recibir cualquier número de valores booleanos. Sería devolver el número de aquellos valores que son verdaderas. Comprobar el resultado de la cantidad de valores que necesita para ser positivo para hacer algo.

trabajar más para que quede claro, no inteligente!

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

    return result;
}

si se refiere a más de o igual a un valor booleano es igual a verdadero, usted podría hacerlo como

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

Si necesita más de una (2 o más) Booleans igual a verdadera, puede intentar

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

Si había millones en lugar de sólo 5 podría evitar Count () y hacer esto en vez ...

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

Si sus banderas se empaquetan en una palabra a continuación, solución de Michael Burr va a funcionar. Sin embargo, el bucle no es necesario:

int moreThanOneBitSet( unsigned int v)
{
    return (v & (v - 1)) != 0;
}

ejemplo

 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

más corto y más feo que la versión Vilx-s:

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

en la parte superior de mi cabeza, un enfoque rápido para este ejemplo concreto; se podría convertir el bool a un int (0 ó 1). a continuación, recorrer termia y sumarlos. si el resultado> = 2, entonces puede ejecutar su función.

Aunque me gusta LINQ, hay algunos agujeros en ella, al igual que este problema.

Haciendo un recuento está muy bien en general, pero puede convertirse en un problema cuando los artículos que su conteo de tomar un tiempo para calcular / recuperar.

El Cualquier () método de extensión está bien si lo que desea es comprobar si hay alguna, pero si usted quiere comprobar por lo menos no hay construido en función de que lo haga y sea perezoso.

Al final, me escribió una función para devolver cierto si hay al menos un cierto número de elementos de la lista.

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

Para usar:

var query = bools.Where(b => b).AtLeast(2);

Esto tiene la ventaja de no tener que evaluar todos los elementos antes de devolver un resultado.

[plug] Mi proyecto, NExtension contiene al menos, Atmost y anulaciones que le permiten mezclar en predicado con el al menos / más cheque. [/ Plug]

La conversión a enteros y sumando debería funcionar, pero es un poco feo y en algunos idiomas no puede ser posible.

¿Qué tal algo así como

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

O si no se preocupan por el espacio, sólo podía calcular previamente la tabla de verdad y utilizar los Bools como índices:

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

Me gustaría hacer algo como esto, con el argumento 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);
}

No es exactamente bastante ... pero aquí hay otra manera de hacerlo:

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

Tengo un mucho mejor una ahora y muy corto!

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

Yo quería dar una respuesta plantilla variadic 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;
}

simplemente llamando de la siguiente crea un método bastante elegante de contar el número de Bools.

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

En la mayoría de los idiomas cierto es equivalente a un valor distinto de cero, mientras que falso es cero. No tengo sintaxis exacta para usted, pero en pseudo código, ¿qué pasa con:

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

Si sólo tiene cinco valores diferentes, se puede fácilmente hacer la prueba por el embalaje de los bits para un corto o un int y la comprobación para ver si se trata de alguna de las respuestas cero o un bit. Los únicos números válidos que usted podría conseguir sería ..

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

Esto le da seis valores para la prospección, los puso en una tabla de consulta y si no está ahí, usted tiene su respuesta.

Esto le da una respuesta 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;
   }

Esto no escala bien más allá de 8 bits, pero sólo tiene cinco.

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

// Más de uno de ellos son verdaderas

...

else

...

Usted ha mencionado

  

Una opción interesante es almacenar los valores booleanos en un byte,   hacer un desplazamiento a la derecha y comparar con el byte inicial.   Algo así como if (myByte && (myByte >> 1))

No creo que la expresión le dará el resultado deseado (por lo menos el uso de la semántica de C, ya que la expresión no es válida C #):

Si (myByte == 0x08), entonces la expresión devolverá cierto a pesar de que sólo hay un conjunto de bits.

Si usted significó "if (myByte & (myByte >> 1))", entonces si (myByte == 0x0a) la expresión volverá falsa a pesar de que hay 2 bits puestos.

Pero aquí hay algunas técnicas para contar el número de bits en una palabra:

Bit haciendo girar Hacks - Contar bits de

Una variación que podría considerar es utilizar el método de conteo de Kernighan, pero rescatar a los principios ya que sólo se necesita saber si hay más de un conjunto de bits:

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

Por supuesto, el uso de una tabla de búsqueda no es una mala opción.

Yo estaba teniendo recientemente esta misma edición, donde tenía tres valores booleanos, que necesitaba para comprobar que sólo 1 de ellos era cierto a la vez. Para ello he utilizado el operador XOR de la siguiente manera:

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

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

Este código generará un error que a y b son ambos verdaderos.

Para referencia: http://www.dotnetperls.com/xor

Sólo acabo de encontrar el operador XOR en C #, si alguien sabe de alguna caídas del hoyo de esta estrategia, por favor hágamelo saber.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top