如果条件 A 匹配,则需要匹配条件 B 才能执行操作 C

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 */
      }
    else
      /* ... */
}
else
{
   /* do action C */
}

是否可以将动作C的代码只写一次而不是两次?

如何简化呢?

你可以这样简化语句:

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

否则将 'C' 的代码放在单独的函数中并调用它:

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

您有两个选择:

  1. 写一个函数执行"action C".

  2. 重新安排你的逻辑,这样你就没有那么多嵌套的 if 语句。问问自己什么条件导致 "action C" 发生。在我看来,它发生在 "condition B" 为真或 "condition A" 为假时。我们可以把它写成 "NOT A OR B"。将其翻译成 C 代码,我们得到

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

要了解有关此类表达式的更多信息,我建议使用谷歌搜索 "boolean algebra"、"predicate logic" 和 "predicate calculus"。这些是深奥的数学主题。您无需全部学习,只需学习基础知识即可。

您还应该了解 "short circuit evaluation"。因此,表达式的顺序对于准确复制原始逻辑很重要。虽然 B || !A 在逻辑上是等价的,但使用它作为条件将在 B 为真时执行 "action C" 而不管 A.

的值如何

呃,这也把我绊倒了,但是由于 我们保证需要 do action C 或 运行 嵌套的-else 块,因此代码可以简化为:

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

这就是我们处理 3 个案例的方式:

  1. 你问题逻辑中的嵌套 do action C 需要 condition Acondition Btrue -- 在这个逻辑中,如果我们达到 2nd term in the if-statement 然后我们知道 condition Atrue 因此我们需要评估的是 condition Btrue
  2. 问题逻辑中嵌套的 else 块要求 condition Atrue 并且 condition Bfalse -- 唯一的方法如果 condition Atrue 并且 condition Bfalse
  3. ,那么我们可以到达 else-block
  4. 您问题逻辑中的外部 else 块要求 condition Afalse -- 在这个逻辑中,如果 condition A 为假,我们也 do action C

Code-Apprentice 在这里纠正我的方法。我建议接受 ,因为他没有编辑就正确地展示了它:/

解决此类问题的第一步始终是建立逻辑table。

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

完成 table 后,解决方案就很明确了。

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

请注意,此逻辑虽然较短,但未来的程序员可能难以维护。

在有模式匹配的语言中,你可以用更直接反映真相的方式表达解决方案-table问题C的答案

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

如果您不熟悉语法,每个模式都由 | 表示后跟要与 (a,b) 匹配的值,下划线用作通配符,表示 "any other values"。由于我们想要做动作 c 以外的事情的唯一情况是当 a 为真且 b 为假时,我们明确地将这些值声明为第一个模式 (true,false),然后在这种情况下做任何应该做的事情。在所有其他情况下,我们进入 "wildcard" 模式并执行操作 c.

问题陈述:

If condition A is matched, condition B needs to be matched in order to do action C

描述implicationA蕴含B,逻辑命题等价至 !A || B(如其他答案中所述):

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

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

尽管已经有很好的答案,但我认为这种方法对于刚接触布尔代数的人来说可能更直观,然后评估一个真值 table。

你首先要看,你要在什么条件下执行C。(a & b)时就是这种情况。还有当!a。 所以你有 (a & b) | !a.

如果你想最小化你可以继续。就像在 "normal" 算术中一样,你可以相乘。

(a & b) | !a = (a | !a) & (b | !a)。 一个 | !a 始终为真,因此您可以将其划掉,从而得到最小化的结果:b | !a。 如果顺序有所不同,因为您只想在 !a 为真时检查 b(例如,当 !a 是空指针检查并且 b 是对指针的操作时,就像@LordFarquaad 在他的评论中指出的那样),您可能想交换两者。

另外一个case (/* ... */) 是c不执行的时候会一直执行,所以我们可以把它放在else case里。

另外值得一提的是,将操作 c 放入方法中的任何一种方式都可能有意义。

这给我们留下了以下代码:

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.
}

通过这种方式,您还可以最小化具有更多操作数的项,这很快就会变得丑陋 tables。另一个好的方法是卡诺图。但我现在不会深入探讨这个问题。

我会将 C 提取到一个方法中,然后在所有情况下尽快退出该函数。 else 如果可能,最后只有一个事物的子句应该几乎总是倒置。这是一个分步示例:

提取 C:

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

先反转 if 先去掉 else:

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

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

去掉第二个else:

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

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

D();

然后你会注意到这两个案例有相同的主体并且可以合并:

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

D();

可选的改进是:

  • 取决于上下文,但如果!A || B令人困惑,请将其提取为一个或多个变量以解释意图

  • C()D() 中的非例外情况应该放在最后,因此如果 D() 是例外情况,则反转 if最后一次

要使代码看起来更像文本,请使用布尔标志。如果逻辑特别晦涩,请添加评论。

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
  {
  ...
  }

在逻辑概念上,你可以这样解决这个问题:

f = a.b + !a
f = ?

作为一个已证明的问题,这导致 f = !a + b。 证明问题的方法有table、Karnaugh Map

因此,在基于 C 的语言中,您可以按如下方式使用:

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

P.S.: Karnaugh Map 也用于更复杂的一系列条件。 这是一种简化布尔代数表达式的方法。

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

使用flags也可以解决这个问题

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