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.