Come posso riformattare la mia condizione per migliorarla?


35

Ho una condizione

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

come posso modificarlo, in modo che possa essere più comprensibile.


1
che valore ha Isirectory quando esiste è falso?
marktani,

1
esiste è di tipo Bool, isDirectory è anche variabili di tipo BOOL
Spynet,

5
if (! isDirectory) ... (esiste ||! esiste) sarà sempre vero.
Squalo,

@Shark - Cosa succede se existse isDirectorysono entrambi veri?
Pasawaya,

Ho letto il titolo come "Ho un problema di personalità, posso cancellare la mia mente per risolverlo". Sì, sono stanco.
Annan,

Risposte:


110

|| è commutativo così

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

è equivalente.

Ora, poiché esiste è sempre vero nella seconda parte del ||è possibile eliminare &&:

if(!exists || !isDirectory)

Oppure puoi fare un passo ulteriore e fare:

if(!(exists && isDirectory))

5
Ciò che è stato implicito ma non esplicitamente menzionato qui è che &&ha una precedenza più alta (almeno nelle lingue più conosciute - ci possono essere eccezioni) rispetto a ||. Quindi a && b || cequivale a (a && b) || cma non a a && (b || c).
Péter Török,

27
Penso che !exists || !isDirectorysia più "comprensibile", perché isDirectorynon può essere vero se !exists. Quindi come umani diremo "se non esiste o [esiste e non] non è una directory".
duros,

6
Preferisco! Esiste || ! isDirectory sull'ultimo.
Apoorv Khurasia,

3
||è commutativo solo se utilizzato su valori senza effetti collaterali - se ad esempio utilizzato con funzioni alcune funzioni potrebbero non essere chiamate (cortocircuito) o restituire un valore diverso in un ordine diverso.
orlp,

26
Chiunque faccia affidamento sulla relativa precedenza di '&&', '||', '==', '! =', Ecc. E non chiarisce la propria intenzione usando le parentesi merita di essere ucciso. In tutte le lingue, qualcosa come "a && b || c 'equivale a un commento che dice che l'autore probabilmente ha rovinato l'intera cosa nella loro corsa per evitare di scrivere qualche personaggio in più.
Brendan,

51

Come processo, suggerisco di costruire una tabella di verità:

e = exists
d = isDirectory

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

Questo corrisponde NANDall'operazione , che è semplicemente:

!(exists && isDirectory)

Se non ricordi tutte le tue porte logiche, wikipedia ha un bel riferimento con le tabelle di verità da avviare .


@Christoffer Hammarström ha sollevato un punto importante sullo stato di isDirectoryessere legato allo stato di exists. Supponendo che si riferiscano allo stesso riferimento e che non sia possibile avere uno stato in cui il riferimento non esiste ed è una directory, la tabella di verità può essere scritta come segue:

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

Il n/aviene utilizzato per rappresentare uno stato che non importa. Riduzioni accettabili potrebbero comportare uno 1o entrambi gli 0stati risultanti n/a.

Con questo in mente, !(exists && isDirectory)è ancora una riduzione valida, risultante in un 1for !e && d.

Tuttavia, !isDirectorysarebbe una riduzione molto più semplice, con conseguente 0per !e && d.


4
Il prossimo passo è rendersi conto che isDirectorydipende da exists. Non può essere sia una directory che non esistere.
Christoffer Hammarström,

@ChristofferHammarstrom, Fuori contesto Non posso presumere che le variabili si riferiscano alla stessa cosa, ma questo è un punto valido. La colonna del risultato deve essere riempita n/anei punti in cui lo stato è impossibile da raggiungere e l'equazione ridotta di conseguenza.
zzzzBov,

Bene, se le variabili si riferiscono a due contesti diversi, sono troppo concise e devono essere rinominate.
Christoffer Hammarström,

Ma costruire una tabella della verità e valutarla è NP-completo!
Thomas Eding,

@ThomasEding, ho due citazioni per te allora, "In teoria, teoria e pratica sono le stesse; in pratica non lo sono." e "L'ottimizzazione prematura è la radice di tutti i mali".
zzzzBov,

22

Per una migliore leggibilità, mi piace estrarre condizioni booleane ai metodi:

if(fileNameUnused())
{...}

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

O con un nome di metodo migliore. Se riesci a nominare correttamente questo metodo, il lettore del tuo codice non ha bisogno di capire cosa significhi la condizione booleana.


+1 per dire qualcosa sui nomi utili. Ma da qualche parte dovrai riformattare il condizionale.
Apoorv Khurasia,

4
Un'alternativa meno estrema, che trasmette ancora intenti, è solo per nominare la condizione utilizzata:boolean fileNameUnused = !exists || !isDirectory; if (fileNameUnused) { doSomething(); }
Steven

8

Potresti semplicemente provare a inchiodare il caso no-go e salvare se questo si presenta.

while(someCondition) {

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

        // the rest of the code
}

o anche

function processFile(someFile)
{ 
    // ...
    if(exists && isDirectory)
       return false;
    // the rest of the code
    // ...
}

La rottura, la continuazione e più di una dichiarazione di ritorno non sono considerate odori di codice?
Freiheit,

8
@Freiheit Dipende dal contesto. A volte viene utilizzata una dichiarazione di ritorno anticipata per ridurre il rientro, migliorando così la leggibilità.
marco-fiset,

La migliore risposta: condizionali complessi sprecano enormi quantità di tempo nella lettura e nella comprensione accurata. Di conseguenza spesso vengono "presi come letti" portando a insidiosi bug.
mattnz,

6

È possibile utilizzare una tabella di verità come indicato. Il secondo passo potrebbe essere una mappa KV per ridurre al minimo il numero di termini.

L'uso delle leggi dell'algebra booleana è un altro approccio:

A = esiste
B =! IsDirectory
! A =! Esiste

&& = *
|| = +

[Modifica]
Una trasformazione più semplice, poiché le operazioni AND e OR sono reciprocamente distributive:

esiste &&! isDirectory || ! esiste
= A * B +! A
= (A +! A) * (B +! A)
= 1 * (B +! A)
= B +! A
[/ Modifica]

esiste &&! isDirectory || ! esiste
= A * B +! A
= A * B +! A * 1 // Identità
= A * B +! A * (B + 1) // Annientatore
= A * B +! A * B +! A / / Distributività e identità
= B * (A +! A) +! A // Distributività
= B * 1 +! A // Complemento 2
= B +! A // Identity
=! IsDirectory || ! esiste

O con doppio complemento (!! 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 || ! esiste


+1 per l'utilizzo delle regole formali (non avrei mai pensato che avrei visto uno di questi dopo il mio primo anno di college).
Nemanja Boric,


5

Non mi piace usare "!" quando c'è più di una condizione nell'espressione. Aggiungerò righe di codice per renderlo più leggibile.

doesNotExist = !exists;
isFile = exists && !isDirecotry;
if (isFile || doesNotExist) 
   {}

+1 Ciò semplifica la lettura come "se è un file o non esiste" che è molto più vicino all'inglese.
Phil,

Questo è un refactoring chiamato Introduce Explaining Variable .
Eddie Gasparian,

1

Come precedentemente indicato, la condizione può essere ridotta a:

if (!(exists && isDirectory))

Tuttavia, scommetto che essere una directory implica l'esistenza. In tal caso, possiamo ridurre la condizione a:

if (!isDirectory)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.