Mi pregunta es:
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
¿Es posible simplemente escribir el código de acción C una vez en lugar de dos?
¿Cómo simplificarlo?
Respuestas:
Su primer paso en este tipo de problemas es siempre hacer una tabla lógica.
Una vez que haya hecho la tabla, la solución es clara.
Tenga en cuenta que esta lógica, aunque más corta, puede ser difícil de mantener para futuros programadores.
fuente
B
tiene efectos secundarios, la tabla lógica tiene que dar cuenta de eso.A && !B
caso sea un no-op:!(A && !B)
es equivalente a lo!A || B
que significa que puede hacerif (!A || B) { /* do action C */ }
y evitar un bloque vacío.if (A && !B)
es realmente difícil de mantener para los futuros programadores, entonces realmente no hay forma de ayudarlos.Tienes dos opciones:
Escriba una función que realice la "acción C".
Reorganice su lógica para que no tenga tantas sentencias if anidadas. Pregúntese qué condiciones causan la "acción C". Me parece que sucede cuando la "condición B" es verdadera o la "condición A" es falsa. Podemos escribir esto como "NO A O B". Traduciendo esto al código C, obtenemos
Para obtener más información sobre este tipo de expresiones, sugiero buscar en Google "álgebra booleana", "lógica de predicados" y "cálculo de predicados". Estos son temas matemáticos profundos. No necesitas aprenderlo todo, solo lo básico.
También debe aprender sobre la "evaluación de cortocircuito". Debido a esto, el orden de las expresiones es importante para duplicar exactamente su lógica original. Si bien
B || !A
es lógicamente equivalente, usar esto como condición ejecutará la "acción C" cuandoB
sea verdadera, independientemente del valor deA
.fuente
...
sea exactamente . Si no es nada en absoluto (es decir, "haga C si se cumplen estas condiciones; de lo contrario no haga nada"), entonces esta es claramente la solución superior, ya que laelse
declaración simplemente puede omitirse por completo en ese momento.Puede simplificar la declaración de esta manera:
De lo contrario, coloque el código para 'C' en una función separada y llámelo:
fuente
if (!A || B)
B || !A
resultarátrue
solo siB
es asítrue
, sin verificar realmenteA
debido a un cortocircuitoA
y quéB
significa.En un lenguaje con coincidencia de patrones, puede expresar la solución de una manera que refleje más directamente la tabla de verdad en la respuesta de QuestionC.
Si no está familiarizado con la sintaxis, cada patrón está representado por un | seguido de los valores para que coincidan con (a, b), y el guión bajo se usa como comodín para significar "cualquier otro valor". Dado que el único caso en el que queremos hacer algo diferente a la acción c es cuando a es verdadero yb es falso, declaramos explícitamente esos valores como el primer patrón (verdadero, falso) y luego hacemos lo que se debe hacer en ese caso. En todos los demás casos, seguimos el patrón de "comodines" y hacemos acciones c.
fuente
La declaración del problema:
describe la implicación : A implica B , una proposición lógica equivalente a
!A || B
(como se menciona en otras respuestas):fuente
inline
para C yconstexpr
también para C ++?Ugh, esto también me hizo tropezar, pero como señaló Code-Apprentice , estamos garantizados que necesitamos
do action C
o ejecutamos elelse
bloque anidado , por lo tanto, el código podría simplificarse para:Así es como estamos llegando a los 3 casos:
do action C
en la lógica de su pregunta necesariacondition A
ycondition B
para sertrue
- En esta lógica, si llegamos al 2 nd plazo en elif
-statement entonces sabemos quecondition A
estrue
por lo tanto todo lo que necesitamos para evaluar es quecondition B
estrue
else
bloque anidado en la lógica de su pregunta requeríacondition A
sertrue
ycondition B
serfalse
. La única forma en que podemos alcanzar elelse
bloque en esta lógica sería sicondition A
fueratrue
ycondition B
fuerafalse
else
bloque externo en la lógica de su pregunta debecondition A
serfalse
: en esta lógica, sicondition A
es falso, tambiéndo action C
Apoyos para Code-Apprentice por enderezarme aquí. Sugeriría aceptar su respuesta , ya que la presentó correctamente sin editar: /
fuente
B
se evaluará solo si!A
es falso. Por lo tanto, ambos deben fallar para ejecutar laselse
declaraciones.!A || B
es falso exactamente cuando ambos!A
yB
son falsos. Por lo tanto,A
será cierto cuando seelse
ejecute. No es necesario reevaluarA
.En el concepto lógico, puede resolver este problema de la siguiente manera:
Como un problema comprobado, esto se traduce en
f = !a + b
. Hay algunas formas de probar el problema, como la tabla de verdad, el mapa de Karnaugh , etc.Entonces, en los lenguajes basados en C, puede usar lo siguiente:
PD: Karnaugh Map también se usa para series de condiciones más complicadas. Es un método para simplificar las expresiones de álgebra booleana.
fuente
Aunque ya hay buenas respuestas, pensé que este enfoque podría ser aún más intuitivo para alguien que es nuevo en el álgebra booleana que evaluar una tabla de verdad.
Lo primero que quiere hacer es mirar, bajo qué condiciones desea ejecutar C. Este es el caso cuando
(a & b)
. También cuando!a
. Entonces tienes(a & b) | !a
.Si quieres minimizar puedes continuar. Al igual que en la aritmética "normal", puede multiplicarse.
(a & b) | !a = (a | !a) & (b | !a)
. a | ! a siempre es cierto, por lo que puedes tacharlo, lo que te deja con el resultado minimizado:b | !a
. En caso de que el orden marque la diferencia, porque desea verificar b solo si! A es verdadero (por ejemplo, cuando! A es una comprobación de puntero nulo yb es una operación en el puntero como @LordFarquaad señaló en su comentario), puede Quiero cambiar los dos.El otro caso (/ * ... * /) siempre se ejecutará cuando c no se ejecute, por lo que podemos ponerlo en el caso else.
También vale la pena mencionar que probablemente tenga sentido de cualquier manera poner la acción c en un método.
Lo que nos deja con el siguiente código:
De esta manera, también puede minimizar los términos con más operandos, lo que rápidamente se vuelve feo con las tablas de verdad. Otro buen enfoque son los mapas de Karnaugh. Pero no voy a profundizar en esto ahora.
fuente
Para que el código se parezca más al texto, use banderas booleanas. Si la lógica es especialmente oscura, agregue comentarios.
fuente
fuente
Extraería C a un método y luego saldría de la función lo antes posible en todos los casos.
else
Las cláusulas con una sola cosa al final casi siempre deben invertirse si es posible. Aquí hay un ejemplo paso a paso:Extracto C:
Invierta primero
if
para deshacerse de primeroelse
:Deshazte de la segunda
else
:Y luego puede notar que los dos casos tienen el mismo cuerpo y se pueden combinar:
Las cosas opcionales para mejorar serían:
depende del contexto, pero si
!A || B
es confuso, extráigalo a una o más variables para explicar la intencióncualquiera de
C()
oD()
es el caso excepcional no debe ir el pasado, así que siD()
es la excepción, luego invierta laif
última vezfuente
Usar banderas también puede resolver este problema
fuente