web-dev-qa-db-fra.com

Si la condition A est vérifiée, la condition B doit l'être pour pouvoir effectuer l'action C

Ma question est:

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

Est-il possible d’écrire le code d’action C une fois au lieu de deux?

Comment le simplifier?

147
starf15h

Votre première étape dans ce genre de problèmes consiste toujours à créer un tableau logique.

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

Une fois que vous avez fait la table, la solution est claire.

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

Notez que cette logique, bien que plus courte, peut être difficile à maintenir pour les futurs programmeurs.

399
QuestionC

Vous avez deux options:

  1. Ecrivez une fonction qui exécute "l'action C".

  2. Réorganisez votre logique de manière à ne pas avoir autant d'instructions if imbriquées. Demandez-vous quelles conditions provoquent "l'action C". Il me semble que cela se produit lorsque la "condition B" est vraie ou la "condition A" est fausse. Nous pouvons écrire ceci comme "NOT A OR B". En traduisant cela en code C, nous obtenons

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

Pour en savoir plus sur ce type d'expressions, je suggère de rechercher dans Google "algèbre booléenne", "logique des prédicats" et "calcul des prédicats". Ce sont des sujets mathématiques profonds. Vous n'avez pas besoin de tout apprendre, seulement les bases.

Vous devriez également vous renseigner sur "l'évaluation des courts-circuits". Pour cette raison, l'ordre des expressions est important pour dupliquer exactement votre logique d'origine. Bien que B || !A soit logiquement équivalent, son utilisation en tant que condition exécutera "l'action C" lorsque B est vrai quelle que soit la valeur de A.

65
Code-Apprentice

Vous pouvez simplifier la déclaration comme ceci:

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

Sinon, mettez le code pour 'C' dans une fonction séparée et appelez-le:

DoActionC()
{
    ....
    // code for Action C
}
if (condition A)
{
    if(condition B)
      {
         DoActionC(); // call the function
      }
    else
      ...
}
else
{
   DoActionC(); // call the function
}
15
CinCout

Dans une langue avec correspondance de motif, vous pouvez exprimer la solution de manière à refléter plus directement la table de vérité dans la réponse de QuestionC.

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

Si vous ne connaissez pas la syntaxe, chaque motif est représenté par un | suivi des valeurs à associer à (a, b), et le trait de soulignement est utilisé comme caractère générique pour signifier "toute autre valeur". Étant donné que le seul cas où nous voulons faire autre chose que l'action c est que a est vrai et que b est faux, nous déclarons explicitement ces valeurs en tant que premier motif (vrai, faux), puis faisons ce qui devrait être fait dans ce cas. Dans tous les autres cas, nous passons au modèle "joker" et faisons l'action c.

14
Aaron M. Eshbach

L'énoncé du problème:

Si la condition A est vérifiée, la condition B doit l'être pour pouvoir effectuer l'action C

décrit implication: UN implique B, proposition logique équivalente à !A || B (comme indiqué dans d'autres réponses):

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

if (implies(/* condition A */,
            /* condition B */))
{
    /* do action C */
}
10
jamesdlin

Dans le concept logique, vous pouvez résoudre ce problème comme suit:

f = a.b +! a
f =?

Comme un problème avéré, cela aboutit à f = !a + b. Il existe quelques moyens de prouver le problème, tels que la table de vérité, Karnaugh Map et ainsi de suite.

Donc, dans les langues basées sur C, vous pouvez utiliser comme suit:

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

P.S .: Carte de Karnaugh est également utilisé pour des séries plus complexes de conditions. C'est une méthode de simplification des expressions d'algèbre booléenne.

6
Siyavash Hamdi

Même s'il existe déjà de bonnes réponses, j'ai pensé que cette approche pourrait être encore plus intuitive pour quelqu'un qui est nouveau en algèbre booléenne puis pour évaluer une table de vérité.

La première chose que vous voulez faire est de regarder dans quelles conditions vous voulez exécuter C. C'est le cas lorsque (a & b). Aussi quand !a. Donc, vous avez (a & b) | !a.

Si vous voulez minimiser, vous pouvez continuer. Tout comme dans l'arithmétique "normale", vous pouvez vous multiplier.

(a & b) | !a = (a | !a) & (b | !a). a | ! a est toujours vrai, vous pouvez donc simplement le rayer, ce qui vous laisse avec le résultat minimisé: b | !a. Dans le cas où l'ordre fait une différence, parce que vous voulez vérifier b uniquement si! A est vraie (par exemple lorsque! A est un contrôle nullpointer et b est une opération sur le pointeur, comme @LordFarquaad l'a souligné dans son commentaire), vous pouvez vouloir passer les deux.

L’autre cas (/ * ... * /) est toujours exécuté lorsque c n’est pas exécuté, nous pouvons donc le placer dans le cas contraire.

Il convient également de mentionner qu'il est probablement logique de mettre l'action c dans une méthode.

Ce qui nous laisse avec le code suivant:

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 cette façon, vous pouvez également réduire les termes avec plus d'opérandes, ce qui devient rapidement moche avec les tables de vérité. Les cartes Karnaugh sont une autre bonne approche. Mais je ne vais pas aller plus loin dans ceci maintenant.

6
deetz

Ugh, cela m'a fait trébucher aussi, mais comme signalé par Code-Apprentice nous sommes assurés d'avoir besoin de do action C ou d'exécuter le bloc imbriqué -else, donc le code pourrait être simplifié à:

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

Voici comment nous abordons les 3 cas:

  1. Le do action C imbriqué dans la logique de votre question demandait que condition A et condition B soit true - Dans cette logique, si nous atteignons la 2dakota du Nord terme dans la déclaration if- alors nous savons que condition A est true ainsi tout ce dont nous avons besoin pour évaluer est que condition B est true
  2. Le bloc imbriqué else- dans la logique de votre question demandait que condition A soit true et condition B soit false - Le seul moyen d'atteindre le else- le bloc dans cette logique serait si condition A étaient true et condition B étaient false
  3. Le bloc externe else- dans la logique de votre question demandait que condition A soit false - Dans cette logique, si condition A est faux, nous aussi do action C

Des accessoires pour Code-Apprentice pour m'avoir redressé ici. Je suggère d'accepter sa réponse , car il l'a présenté correctement sans édition: /

6
Jonathan Mee

Pour que le code ressemble davantage à du texte, utilisez des drapeaux booléens. Si la logique est particulièrement obscure, ajoutez des commentaires.

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
anatolyg
if((A && B ) || !A)
{
  //do C
}
else if(!B)
{
  //...
}
3
Ali

Je voudrais extraire C à une méthode, puis quitte la fonction dès que possible dans tous les cas. Les clauses else avec une seule chose à la fin devraient presque toujours être inversées si possible. Voici un exemple étape par étape:

Extrait C:

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

Inverser le premier if pour se débarrasser du premier else:

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

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

Débarrassez-vous de la seconde else:

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

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

D();

Et puis, vous remarquerez que les deux cas ont le même corps et peuvent être combinés:

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

D();

Les choses facultatives à améliorer seraient:

  • dépend du contexte, mais si !A || B est déroutant, extrayez-le en une ou plusieurs variables pour expliquer l'intention

  • quelle que soit celle de C() ou D(), le cas non exceptionnel doit aller en dernier lieu; ainsi, si D() est l'exception, alors inversez la if une dernière fois.

2
Dave Cousineau

L'utilisation de drapeaux peut également résoudre ce problème

int flag = 1; 
if ( condition A ) {
    flag = 2;
    if( condition B ) {
        flag = 3;
    }
}
if(flag != 2) { 
    do action C 
}
2
Spr k