Jak mogę sformatować swój stan, aby był lepszy?

35

Mam warunek

if(exists && !isDirectory || !exists)
{}

jak mogę go zmodyfikować, aby był bardziej zrozumiały.

Spynet
źródło
1
jaka wartość ma isDirectory, gdy istnieje, jest fałszywa?
marktani
1
istnieje typ Bool, isDirectory to także zmienne typu BOOL
Spynet
5
if (! isDirectory) ... (istnieje ||! istnieje) zawsze będzie prawdziwe.
Shark
@Shark - Co, jeśli existsi isDirectoryczy oba są prawdziwe?
pasawaya
Przeczytałem ten tytuł: „Mam problem z osobowością, czy mogę wymazać umysł, aby go naprawić”. Tak, jestem zmęczony.
Annan

Odpowiedzi:

110

|| jest więc przemienny

if(!exists || (exists && !isDirectory))

jest równoważne.

Teraz, ponieważ istnieje jest zawsze prawdziwe w drugiej części ||możesz upuścić &&:

if(!exists || !isDirectory)

Możesz też pójść o krok dalej i zrobić:

if(!(exists && isDirectory))
maniak zapadkowy
źródło
5
Sugerowano, ale nie wspomniano tutaj wyraźnie, że &&ma wyższy priorytet (przynajmniej w najbardziej znanych językach - mogą istnieć wyjątki) niż ||. a && b || cJest to więc równoważne, (a && b) || cale nie a && (b || c).
Péter Török
27
Myślę, że !exists || !isDirectoryjest to bardziej „zrozumiałe”, ponieważ isDirectorynie może być prawdą, jeśli !exists. Więc jako człowiek powiemy „jeśli nie istnieje lub [istnieje i nie jest katalogiem”.
duros
6
Wolę! Istnieje || ! isDirectory w stosunku do ostatniego.
Apoorv Khurasia
3
||jest przemienny tylko wtedy, gdy jest stosowany w przypadku wartości bez skutków ubocznych - jeśli na przykład jest używany z funkcjami, niektóre funkcje mogą nie zostać wywołane (zwarcie) lub zwrócić inną wartość w innej kolejności.
orlp
26
Każdy, kto opiera się na względnym pierwszeństwie „&&”, „||”, „==”, „! =” Itd. I nie wyrazi swojej intencji przy użyciu nawiasów, zasługuje na zastrzelenie. We wszystkich językach coś w stylu „a&&b || c 'jest równoważne komentarzowi mówiącemu, że autor prawdopodobnie spieprzył całą rzecz w pośpiechu, aby uniknąć wpisywania kilku dodatkowych znaków.
Brendan
51

Jako proces sugeruję zbudowanie tabeli prawdy:

e = exists
d = isDirectory

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | 1
1 | 0 | 1
1 | 1 | 0

Jest to zgodne z NANDoperacją , która jest po prostu:

!(exists && isDirectory)

Jeśli nie pamiętasz wszystkich swoich bramek logicznych, wikipedia ma ładny odnośnik z tabelami prawdy do uruchomienia .


@Christoffer Hammarström poruszył ważną kwestię dotyczącą stanu isDirectoryprzywiązania do tego stanu exists. Zakładając, że odnoszą się do tego samego odwołania i że nie jest możliwe, aby stan, w którym odwołanie nie istnieje i jest katalogiem, tabelę prawdy można zapisać w następujący sposób:

e | d | (e && !d) || !e
--+---+----------------
0 | 0 | 1
0 | 1 | n/a
1 | 0 | 1
1 | 1 | 0

n/aJest używany do reprezentowania stanu, że nie ma znaczenia. Dopuszczalne redukcje mogą skutkować skutkiem jednego 1lub obu 0stanów n/a.

Mając to na uwadze, !(exists && isDirectory)nadal obowiązuje ważna redukcja, w wyniku której powstaje 1for !e && d.

Jednak !isDirectorybyłoby o wiele prostsze redukcji, w wyniku czego 0na !e && d.

zzzzBov
źródło
4
Następnym krokiem jest uświadomienie sobie, że to isDirectoryzależy exists. Nie może być jednocześnie katalogiem i nie istnieje.
Christoffer Hammarström
@ChristofferHammarstrom, Poza kontekstem Nie mogę założyć, że zmienne odnoszą się do tej samej rzeczy, ale to jest poprawny punkt. Kolumnę wyników należy wypełnić n/aw miejscach, w których nie można osiągnąć stanu, a równanie odpowiednio zmniejszyć.
zzzzBov
Cóż, jeśli zmienne odnoszą się do dwóch różnych kontekstów, to są one zbyt zwięzłe i trzeba je zmienić.
Christoffer Hammarström
Ale budowanie tabeli prawdy i ocenianie jej jest NP-zakończone!
Thomas Eding
@ThomasEding, mam dla ciebie dwa cytaty: „W teorii teoria i praktyka są takie same; w praktyce nie są”. oraz „Przedwczesna optymalizacja jest źródłem wszelkiego zła”.
zzzzBov,
22

Dla lepszej czytelności lubię wyodrębniać warunki boolowskie do metod:

if(fileNameUnused())
{...}

public boolean fileNameUnused() {
   return exists && !isDirectory || !exists;
}

Lub z lepszą nazwą metody. Jeśli potrafisz poprawnie nazwać tę metodę, czytnik twojego kodu nie musi odgadnąć, co oznacza warunek logiczny.

Puckl
źródło
+1 za powiedzenie czegoś o przydatnych nazwach. Ale gdzieś trzeba będzie sformatować warunek.
Apoorv Khurasia
4
Mniej ekstremalną alternatywą, która wciąż przekazuje zamiar, jest tylko określenie zastosowanego warunku:boolean fileNameUnused = !exists || !isDirectory; if (fileNameUnused) { doSomething(); }
Steven,
8

Możesz po prostu spróbować przybić skrzynkę no-go i wpłacić kaucję, jeśli się pojawi.

while(someCondition) {

    if(exists && isDirectory)
        continue;
        // maybe "break", depends on what you're after.

        // the rest of the code
}

lub nawet

function processFile(someFile)
{ 
    // ...
    if(exists && isDirectory)
       return false;
    // the rest of the code
    // ...
}
ZJR
źródło
Czy przerwa, kontynuacja i więcej niż jedna instrukcja zwrotna nie są uważane za zapach?
Freiheit,
8
@ Freiheit To zależy od kontekstu. Czasami stosuje się instrukcję wczesnego powrotu w celu zmniejszenia wcięcia, zwiększając w ten sposób czytelność.
marco-fiset
Najlepsza odpowiedź - złożone warunki warunkowe marnują ogromne ilości czasu na czytanie i dokładne ich zrozumienie. W rezultacie często są „traktowane jako przeczytane”, co prowadzi do podstępnych błędów.
mattnz
6

Możesz użyć tabeli prawdy, jak wskazano. Drugim krokiem może być mapa KV dla zminimalizowania liczby terminów.

Korzystanie z praw algebry boolowskiej to kolejne podejście:

A = istnieje
B =! IsDirectory
! A =! Istnieje

&& = *
|| = +

[Edytuj]
Prostsza transformacja, ponieważ operacje AND i OR dzielą się wzajemnie:

istnieje &&! isDirectory || ! istnieje
= A * B +! A
= (A +! A) * (B +! A)
= 1 * (B +! A)
= B +! A
[/ Edytuj]

istnieje &&! isDirectory || ! istnieje
= A * B +! A
= A * B +! A * 1 // Tożsamość
= A * B +! A * (B + 1) // Annihilator
= A * B +! A * B +! A / / Dystrybucja i tożsamość
= B * (A +! A) +! A // Dystrybucja
= B * 1 +! A // Uzupełnienie 2
= B +! A // Tożsamość
=! IsDirectory || ! istnieje

Lub z podwójnym uzupełnieniem (!! x = x):

A * B +! A
= !! (A * B +! A)
=! (! (A * B) * A)
=! ((! A +! B) * A)
=! (! A * A + ! B * A)
=! (0 +! B * A)
=! (! B * A)
= B +! A
=! IsDirectory || ! istnieje

Eddie Gasparian
źródło
+1 za stosowanie formalnych zasad (nigdy nie sądziłem, że zobaczę jedną z nich po pierwszym roku studiów).
Nemanja Boric
5

Nie lubię używać „!” gdy w wyrażeniu występuje więcej niż jeden warunek. Dodam wiersze kodu, aby był bardziej czytelny.

doesNotExist = !exists;
isFile = exists && !isDirecotry;
if (isFile || doesNotExist) 
   {}
David W.
źródło
+1 Ułatwia to odczytanie „jeśli plik jest lub nie istnieje”, co jest znacznie bliższe językowi angielskiemu.
Phil
Jest to refaktoryzacja o nazwie Wprowadzenie zmiennej objaśniającej .
Eddie Gasparian
1

Jak wskazano wcześniej, warunek można sprowadzić do:

if (!(exists && isDirectory))

Założę się jednak, że bycie katalogiem oznacza istnienie. Jeśli tak, możemy zredukować ten warunek do:

if (!isDirectory)
Jack Applin
źródło