Si la condición A coincide, la condición B debe coincidir para realizar la acción C


Mi pregunta es:

if (/* condition A */)
{
    if(/* condition B */)
      {
         /* do action C */
      }
    else
      /* ... */
}
else
{
   /* do action C */
}

¿Es posible escribir el código de acción C una sola vez en lugar de dos veces?

Cómo simplificarlo?

Author: Siyavash Hamdi, 2017-07-20

12 answers

El primer paso en este tipo de problemas es siempre hacer una tabla lógica.

A | B | Result
-------------------
T | T | do action C
T | F | ...
F | T | do action C
F | F | do action C

Una vez que haya hecho la tabla, la solución está clara.

if (A && !B) {
  ...
}
else {
  do action C
}

Tenga en cuenta que esta lógica, aunque más corta, puede ser difícil de mantener para los futuros programadores.

 399
Author: QuestionC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-21 02:21:03

Tienes dos opciones:

  1. Escriba una función que realice "acción C".

  2. Reorganiza tu lógica para que no tengas tantas sentencias if anidadas. Pregúntese qué condiciones causan que ocurra 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

    if (!A || B) {
        action C
    } else {
        ...
    }
    

Para aprender más sobre este tipo de expresiones, sugiero googling "boolean algebra", "predicate logic", and "predicate calculus". Estos son temas matemáticos profundos. No necesitas aprender todo, solo lo básico.

También debe aprender sobre la "evaluación de cortocircuitos". Debido a esto, el orden de las expresiones es importante para duplicar exactamente su lógica original. Mientras que B || !A es lógicamente equivalente, usar esto como condición ejecutará "acción C" cuando B es verdadero independientemente del valor de A.

 65
Author: Code-Apprentice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-20 04:01:19

Puede simplificar la declaración de esta manera:

if ((A && B) || (!A)) // or simplified to (!A || B) as suggested in comments
{
    do C
}

De lo contrario ponga el código para ' C ' en una función separada y llámelo:

DoActionC()
{
    ....
    // code for Action C
}
if (condition A)
{
    if(condition B)
      {
         DoActionC(); // call the function
      }
    else
      ...
}
else
{
   DoActionC(); // call the function
}
 15
Author: CinCout,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-20 03:31:30

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.

match (a,b) with
| (true,false) -> ...
| _ -> action c

Si no está familiarizado con la sintaxis, cada patrón está representado por un | seguido de los valores que coinciden con (a,b), y el subrayado se usa como comodín para significar "cualquier otro valor". Dado que el único caso en el que queremos hacer algo que no sea la acción c es cuando a es verdadero y b es falso, declaramos explícitamente esos valores como el primer patrón (verdadero, falso) y luego hacer lo que se debe hacer en ese caso. En todos los demás casos, caemos a través del patrón "comodín" y hacemos la acción c.

 14
Author: Aaron M. Eshbach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-20 21:06:12

La declaración del problema:

Si la condición A coincide, la condición B debe coincidir para realizar la acción C

Describe implicación: A implica B , una proposición lógica equivalente a !A || B (como se menciona en otras respuestas):

bool implies(bool p, bool q) { return !p || q; }

if (implies(/* condition A */,
            /* condition B */))
{
    /* do action C */
}
 10
Author: jamesdlin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-21 20:17:08

Ugh, esto también me hizo tropezar, pero como señaló Code-Apprentice tenemos garantizada la necesidad de do action C o ejecutar el bloque anidado - else, por lo que el código podría simplificarse a:

if (not condition A or condition B) {
    do action C
} else {
    ...
}

Así es como estamos golpeando los 3 casos:

  1. El do action C anidado en la lógica de su pregunta requería condition A y condition B ser true In En esta lógica, si alcanzamos el término 2nd en la declaración if entonces sabemos que condition A es true por lo tanto, todo lo que necesitamos evaluar es que condition B es true
  2. El else-bloque anidado en la lógica de su pregunta requiere condition A ser true y condition B ser false The La única forma en que podemos llegar al else-bloque en esta lógica sería si condition A fueran true y condition B fueran false]}
  3. El bloque exterior else en la lógica de su pregunta requiere condition A ser false} En esta lógica si condition A es falso también do action C
Utilería para Aprendiz de código por enderezarme aquí. Yo sugeriría aceptar su respuesta , ya que lo presentó correctamente sin editar: /
 6
Author: Jonathan Mee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-20 03:53:46

En el concepto de lógica, puede resolver este problema de la siguiente manera:

F = a. b+!un
f=?

Como un problema comprobado, esto resulta en f = !a + b. Hay algunas maneras de probar el problema como la tabla de la verdad, Mapa de Karnaugh y así sucesivamente.

Así que en lenguajes basados en C se puede usar de la siguiente manera:

if(!a || b)
{
   // Do action C
}

P.d.: El mapa de Karnaugh también se usa para series de condiciones más complicadas. Es un método para simplificar el álgebra booleana expresiones.

 6
Author: Siyavash Hamdi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-26 06:17:48

A pesar de que 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 desea hacer es mirar, bajo qué condiciones desea ejecutar C. Este es el caso cuando (a & b). También cuando !a. Así que tienes (a & b) | !a.

Si quieres minimizar puedes continuar. Al igual que en la aritmética" normal", se puede multiplicar.

(a & b) | !a = (a | !a) & (b | !a). a/!a siempre es verdad, así que puede tacharlo, lo que le deja con el resultado minimizado: b | !a. En caso de que el pedido haga una diferencia, porque desea comprobar b solo si !a es verdadero (por ejemplo cuando!a es una comprobación de nullpointer y b es una operación en el puntero como @LordFarquaad señaló en su comentario), es posible que desee cambiar los dos.

El otro caso (/* ... * / ) se ejecutará siempre 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:

if (!A || B)
{
    doActionC()  // execute method which does action C
}
else
{
   /* ... */ // what ever happens here, you might want to put it into a method, too.
}

De esta manera también puede minimizar los términos con más operandos, lo que rápidamente se pone feo con las tablas de verdad. Otro buen enfoque son los mapas de Karnaugh. Pero no profundizaré en esto ahora.

 6
Author: deetz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-14 09:29:59

Para hacer que el código se parezca más al texto, use banderas booleanas. Si la lógica es especialmente oscura, agregue comentarios.

bool do_action_C;

// Determine whether we need to do action C or just do the "..." action
// If condition A is matched, condition B needs to be matched in order to do action C
if (/* condition A */)
{
    if(/* condition B */)
      do_action_C = true; // have to do action C because blah
    else
      do_action_C = false; // no need to do action C because blarg
}
else
{
  do_action_C = true; // A is false, so obviously have to do action C
}

if (do_action_C)
  {
     DoActionC(); // call the function
  }
else
  {
  ...
  }
 4
Author: anatolyg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-23 18:13:06
if((A && B ) || !A)
{
  //do C
}
else if(!B)
{
  //...
}
 3
Author: Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-03 13:44:17

Me gustaría extraer C a un método, y luego salir de la función tan pronto como sea posible en todos los casos. else las cláusulas con una sola cosa al final casi siempre deben invertirse si es posible. He aquí un ejemplo paso a paso:

Extracto C:

if (A) {
   if (B)
      C();
   else
      D();
} else
   C();

Invertir primero if para deshacerse de primero else:

if (!A) {
   C();
   return;
}

if (B)
   C();
else
   D();

Deshacerse de segundo else:

if (!A) {
   C();
   return;
}

if (B) {
   C();
   return;
} 

D();

Y entonces usted puede notar que los dos casos tienen el mismo cuerpo y se pueden combinar:{[14]]}

if (!A || B) {
   C();
   return;
}

D();

Cosas opcionales para mejorar sería:

  • Depende del contexto, pero si !A || B es confuso, extráigalo a una o más variables para explicar la intención

  • Cualquiera de C() o D() que sea el caso no excepcional debe ir en último lugar, por lo que si D() es la excepción, entonces invierta el if una última vez

 2
Author: Dave Cousineau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-23 02:14:20

El uso de banderas también puede resolver este problema

int flag = 1; 
if ( condition A ) {
    flag = 2;
    if( condition B ) {
        flag = 3;
    }
}
if(flag != 2) { 
    do action C 
}
 2
Author: Spr k,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-17 00:52:27