¿La forma más fácil de voltear un valor booleano?

124

Solo quiero voltear un booleano basado en lo que ya es. Si es verdad, hazlo falso. Si es falso, hazlo verdadero.

Aquí está mi extracto de código:

switch(wParam) {

case VK_F11:
  if (flipVal == true) {
     flipVal = false;
  } else {
    flipVal = true;
  }
break;

case VK_F12:
  if (otherVal == true) {
     otherValVal = false;
  } else {
    otherVal = true;
  }
break;

default:
break;
}
John T
fuente

Respuestas:

341

Puede voltear un valor así:

myVal = !myVal;

entonces su código se acortaría a:

switch(wParam) {
    case VK_F11:
    flipVal = !flipVal;
    break;

    case VK_F12:
    otherVal = !otherVal;
    break;

    default:
    break;
}
John T
fuente
77
No solo esta es la forma más fácil, sino también la más limpia.
Sharptooth
los dos casos pueden fusionarse ya que hacen lo mismo.
David Allan Finch el
1
Es el valor predeterminado: descanso; ¿realmente necesario? ¿El interruptor no terminará igual sin él?
Chris Lutz
12
Predeterminado: descanso; es innecesario
Rob K
44
Si está alternando algo de largo aliento como object1-> system1.system2.system3.parameter1, puede ser útil tener una macro TOGGLE (a). Esto evita algunos errores y lo hace más legible en pantallas estrechas.
OJW
77

¡Claramente necesitas un patrón de fábrica!

KeyFactory keyFactory = new KeyFactory();
KeyObj keyObj = keyFactory.getKeyObj(wParam);
keyObj.doStuff();


class VK_F11 extends KeyObj {
   boolean val;
   public void doStuff() {
      val = !val;
   }
}

class VK_F12 extends KeyObj {
   boolean val;
   public void doStuff() {
      val = !val;
   }
}

class KeyFactory {
   public KeyObj getKeyObj(int param) {
      switch(param) {
         case VK_F11:
            return new VK_F11();
         case VK_F12:
            return new VK_F12();
      }
      throw new KeyNotFoundException("Key " + param + " was not found!");
   }
}

:RE

</sarcasm>
Dibujó
fuente
9
Probablemente también podríamos agregar el patrón singleton para la fábrica.
Drew
@Orm Porque eres un ORM ? :)
mlvljr
3
¡Tenga en cuenta la sutil recomendación de cambiar a Java!
Caracol mecánico
Bueno ... creo que necesitamos otro lanzamiento importante de C ++ para este, puede ser C ++ / 51
0x6900
¡Hola chicos! Creo que su enfoque no es reentrante. Necesita al menos atomic_bool, mejor un mutex o una cola de eventos. Además, necesitamos un patrón observador para monitorear el estado de val.
Marco Freudenberger
38

Si sabe que los valores son 0 o 1, podría hacerlo flipval ^= 1.

Mike Dunlavey
fuente
1
¿Por qué usar un operador bit a bit para una operación lógica? Huele a ofuscación innecesaria para mí.
Mark Pim
55
@ Mark: Lo siento. Supongo que estoy pasado de moda. Pero ayuda si su expresión de valor L es realmente larga, por lo que no tiene que repetirla. Además, podría decir flipval ^ = TRUE. ¿Eso está mejor?
Mike Dunlavey el
66
@Alnitak: Tienes razón en algunas circunstancias. He visto a algunas personas empacar partes para "ahorrar espacio" y actuar como si las instrucciones para acceder a ellas no ocuparan espacio.
Mike Dunlavey el
2
@ Albert: ^es el operador exclusivo . 0^1es 1, y 1^1es 0. Es lo mismo que agregar si ignoras el bit de acarreo. O puede pensarlo como: si un bit es 1, el resultado es el inverso del otro bit. O puede pensar que se trata de hacer la pregunta: ¿Son estos dos bits diferentes?
Mike Dunlavey
1
@MikeDunlavey si estás en un dispositivo con 4M de Flash para espacio de código y 3K de SRAM para espacio de datos, ¡esa es una forma justificada de actuar!
MM
33

La solución más fácil que encontré:

x ^= true;
xamid
fuente
11
x = !x;No solo es más corto, sino también más legible.
Rodrigo
13
Tenga en cuenta que, por ejemplo, longVariableName ^= true;es claramente más corto que longVariableName = !longVariableName;Y cada programador debe saber XOR.
xamid
a ^= bsignifica a = a ^ b, donde ^significa XOR. La notación a °= bpara a = a ° bcualquier operador °es muy común entre la sintaxis C / C ++ / C #.
xamid
2
Anecdótico, pero recientemente me encontré con la línea. gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value = !gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value;Por supuesto, lo más limpio es expandirlo a varias líneas y usar variables temporales para almacenar los objetos, pero gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value ^= 1es mucho más legible, menos propenso a errores y menos caracteres que el código original. .
Vortico
1
Además, menos duplicación significa menos posibilidades de olvidarse de actualizar AMBOS lados de la ecuación durante los cambios rápidos de desarrollo / días largos / noches de codificación.
Katastic Voyage
11

Solo para información: si en lugar de un número entero su campo requerido es un solo bit dentro de un tipo más grande, use el operador 'xor' en su lugar:

int flags;

int flag_a = 0x01;
int flag_b = 0x02;
int flag_c = 0x04;

/* I want to flip 'flag_b' without touching 'flag_a' or 'flag_c' */
flags ^= flag_b;

/* I want to set 'flag_b' */
flags |= flag_b;

/* I want to clear (or 'reset') 'flag_b' */
flags &= ~flag_b;

/* I want to test 'flag_b' */
bool b_is_set = (flags & flag_b) != 0;
Alnitak
fuente
9

Esto parece ser un juego para todos ... Je. Aquí hay otra vacación, que supongo que está más en la categoría "inteligente" que algo que recomendaría para el código de producción:

flipVal ^= (wParam == VK_F11);
otherVal ^= (wParam == VK_F12);

Supongo que sus ventajas son:

  • Muy conciso
  • No requiere ramificación

Y una desventaja igual de obvia es

  • Muy conciso

Esto está cerca de la solución de @ korona usando?: Pero dado un paso (pequeño) más allá.

relajarse
fuente
2
Por orden de operaciones, creo que puede omitir el paréntesis para ser aún más conciso. : O
Drew
8

Solo porque mi forma favorita de alternar una bola no está en la lista ...

bool x = true;
x = x == false;

también funciona :)

(sí, x = !x;es más claro y más fácil de leer)

Rozwel
fuente
6

La solución codegolf'ish sería más como:

flipVal = (wParam == VK_F11) ? !flipVal : flipVal;
otherVal = (wParam == VK_F12) ? !otherVal : otherVal;
korona
fuente
2

Prefiero la solución de John T, pero si quieres ir a todo golf, tu declaración se reduce lógicamente a esto:

//if key is down, toggle the boolean, else leave it alone.
flipVal = ((wParam==VK_F11) && !flipVal) || (!(wParam==VK_F11) && flipVal);
if(wParam==VK_F11) Break;

//if key is down, toggle the boolean, else leave it alone.
otherVal = ((wParam==VK_F12) && !otherVal) || (!(wParam==VK_F12) && otherVal);
if(wParam==VK_F12) Break;
JosephStyons
fuente
¿No tienes que verificar wParam contra VK_F11 y VK_F12?
drby
2
flipVal ^= 1;

lo mismo va para

otherVal
evandrix
fuente
0

Claramente, necesita una solución flexible que pueda admitir tipos enmascarados como booleanos. Lo siguiente permite eso:

template<typename T>    bool Flip(const T& t);

Luego puede especializar esto para diferentes tipos que pueden pretender ser booleanos. Por ejemplo:

template<>  bool Flip<bool>(const bool& b)  { return !b; }
template<>  bool Flip<int>(const int& i)    { return !(i == 0); }

Un ejemplo de uso de esta construcción:

if(Flip(false))  { printf("flipped false\n"); }
if(!Flip(true))  { printf("flipped true\n"); }

if(Flip(0))  { printf("flipped 0\n"); }
if(!Flip(1)) { printf("flipped 1\n"); }

No, no hablo en serio.

dma
fuente
0

Para enteros con valores de 0 y 1 puede intentar:

value = abs(value - 1);

MWE en C:

#include <stdio.h>
#include <stdlib.h>
int main()
{
        printf("Hello, World!\n");
        int value = 0;
        int i;
        for (i=0; i<10; i++)
        {
                value = abs(value -1);
                printf("%d\n", value);
        }
        return 0;
}
Artur
fuente
0

Solo porque me gusta cuestionar el código. Propongo que también puede hacer uso del ternario haciendo algo como esto:

Ejemplo:

bool flipValue = false;
bool bShouldFlip = true;
flipValue = bShouldFlip ? !flipValue : flipValue;
Jon Black
fuente