Najłatwiejszy sposób na odwrócenie wartości logicznej?

125

Chcę tylko odwrócić wartość logiczną na podstawie tego, czym już jest. Jeśli to prawda - zrób to fałszywie. Jeśli to fałsz - uczyń to prawdą.

Oto mój fragment kodu:

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
źródło

Odpowiedzi:

341

Możesz odwrócić wartość w następujący sposób:

myVal = !myVal;

więc twój kod skróciłby się do:

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

    case VK_F12:
    otherVal = !otherVal;
    break;

    default:
    break;
}
John T
źródło
7
Nie tylko to najłatwiejszy, ale i najczystszy sposób.
ostry
te dwa przypadki można łączyć, ponieważ robią to samo.
David Allan Finch
1
Domyślnie: przerwa; naprawdę konieczne? Czy bez tego przełącznik nie skończy się tak samo?
Chris Lutz,
12
Domyślnie: przerwa; jest niepotrzebne.
Rob K
4
Jeśli przełączasz coś rozwlekłego, jak obiekt1-> system1.system2.system3.parameter1, pomocne może być makro TOGGLE (a). Zapobiega to niektórym błędom i sprawia, że ​​wszystko jest bardziej czytelne na wąskich ekranach.
OJ Ś
77

Oczywiście potrzebujesz wzoru fabrycznego!

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>
Rysował
źródło
9
Prawdopodobnie moglibyśmy dodać wzorzec singletona również dla fabryki.
Drew
@Orm Bo jesteś ORM ? :)
mlvljr
3
Zwróć uwagę na subtelne zalecenie przejścia na Javę!
Mechaniczny ślimak
Cóż ... myślę, że potrzebujemy innego głównego wydania C ++ do tego, może to być C ++ / 51
0x6900
Cześć ludzie! Myślę, że twoje podejście nie jest powtórne. Potrzebujesz przynajmniej atomic_bool, lepiej muteksu lub kolejki zdarzeń. Ponadto potrzebujemy wzorca obserwatora do monitorowania stanu val.
Marco Freudenberger
39

Jeśli wiesz, że wartości to 0 lub 1, możesz to zrobić flipval ^= 1.

Mike Dunlavey
źródło
1
Po co używać operatora bitowego do operacji logicznej? Dla mnie pachnie niepotrzebnym zaciemnianiem.
Mark Pim
5
@Mark: Przepraszam. Chyba jestem staroświecki. Ale to pomaga, jeśli twoje wyrażenie wartości L jest naprawdę długie, więc nie musisz tego powtarzać. Możesz także powiedzieć flipval ^ = TRUE. Czy to jest lepsze?
Mike Dunlavey
6
@Alnitak: W pewnych okolicznościach masz rację. Widziałem ludzi pakujących bity razem, aby „zaoszczędzić miejsce” i zachowywać się tak, jakby instrukcje dostępu do nich nie zajmowały miejsca.
Mike Dunlavey
2
@Albert: ^jest operatorem na wyłączność lub . 0^1jest 1i 1^1jest 0. To to samo, co dodawanie, jeśli zignorujesz bit przenoszenia. Lub możesz o tym myśleć tak, jakby - jeśli jeden z bitów ma wartość 1, wynik jest odwrotnością drugiego bitu. Lub możesz o tym myśleć jako o zadawaniu pytania: czy te dwa bity są różne?
Mike Dunlavey
1
@MikeDunlavey, jeśli korzystasz z urządzenia z 4 MB pamięci Flash dla przestrzeni kodowej i 3 KB pamięci SRAM dla przestrzeni danych, to jest to uzasadniony sposób działania!
MM,
33

Najłatwiejsze rozwiązanie, które znalazłem:

x ^= true;
xamid
źródło
12
x = !x;jest nie tylko krótszy, ale także bardziej czytelny.
Rodrigo
13
Zauważ, że np. longVariableName ^= true;Jest wyraźnie krótszy niż longVariableName = !longVariableName;I każdy programista powinien znać XOR.
xamid
a ^= boznacza a = a ^ b, gdzie ^oznacza XOR. Notacja a °= bdla a = a ° bdowolnego operatora °jest bardzo powszechna w składni C / C ++ / C #.
xamid
2
Anegdotyczne, ale ostatnio natknąłem się na tę linię gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value = !gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value;Oczywiście najczystszą rzeczą do zrobienia jest rozszerzenie jej na wiele linii i użycie zmiennych tymczasowych do przechowywania obiektów, ale gRackWidget->modules->first().lights[PATTERN1_LIGHT + i].value ^= 1jest dużo bardziej czytelny, mniej podatny na błędy i mniej znaków niż oryginalny kod .
Vortico
1
Ponadto mniej duplikatów oznacza mniejsze szanse na zapomnienie o zaktualizowaniu OBU stron równania podczas szybkich zmian rozwojowych / długich dni / nocy kodowania.
Katastic Voyage,
11

Tylko dla informacji - jeśli zamiast liczby całkowitej wymagane pole jest jednym bitem w większym typie, użyj zamiast tego operatora „xor”:

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
źródło
9

To wydaje się być darmowe dla wszystkich ... Heh. Oto kolejna odmiana, która, jak sądzę, jest bardziej w kategorii „sprytny” niż coś, co poleciłbym do kodu produkcyjnego:

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

Myślę, że jego zalety to:

  • Bardzo zwięzłe
  • Nie wymaga rozgałęziania

I równie oczywista jest wada

  • Bardzo zwięzłe

Jest to bliskie rozwiązaniu @ korona używającego?: Ale poszło o jeden (mały) krok dalej.

rozwijać
źródło
2
Według kolejności operacji myślę, że możesz pominąć nawiasy, aby uzyskać jeszcze bardziej zwięzłe informacje. : O
Drew
8

Tylko dlatego, że mój ulubiony dziwny sposób na przełączanie bool nie jest wymieniony ...

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

działa też. :)

(tak, x = !x;jest jaśniejszy i łatwiejszy do odczytania)

Rozwel
źródło
6

Codegolf'owe rozwiązanie byłoby bardziej podobne do:

flipVal = (wParam == VK_F11) ? !flipVal : flipVal;
otherVal = (wParam == VK_F12) ? !otherVal : otherVal;
korona
źródło
2

Wolę rozwiązanie Johna T, ale jeśli chcesz zagrać w kodowanie, twoje stwierdzenie logicznie sprowadza się do tego:

//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
źródło
Nie musisz porównywać wParam z VK_F11 i VK_F12?
drby
2
flipVal ^= 1;

to samo dotyczy

otherVal
evandrix
źródło
0

Oczywiście potrzebujesz elastycznego rozwiązania, które może obsługiwać typy maskujące jako wartości logiczne. Umożliwia to:

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

Następnie możesz specjalizować się w tym dla różnych typów, które mogą udawać, że są logiczne. Na przykład:

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

Przykład użycia tej konstrukcji:

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

Nie, nie mówię poważnie.

dma
źródło
0

W przypadku liczb całkowitych o wartościach 0 i 1 możesz spróbować:

value = abs(value - 1);

MWE w 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
źródło
0

Tylko dlatego, że lubię kwestionować kod. Proponuję, abyś mógł również skorzystać z trójskładnika, robiąc coś takiego:

Przykład:

bool flipValue = false;
bool bShouldFlip = true;
flipValue = bShouldFlip ? !flipValue : flipValue;
Jon Black
źródło