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

我的问题是:

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

有没有可能只写一次而不是两次行动 C 的代码?

如何简化它?

13895 次浏览

你可以像这样简化这句话:

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 语句。问问自己是什么条件导致了“行动 C”的发生。在我看来,当“条件 B”为真或“条件 A”为假时,就会发生这种情况。我们可以把它写成“非 A 或 B”。把这个转换成 C 代码,我们得到

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

To learn more about these kind of expressions, I suggest googling "boolean algebra", "predicate logic", and "predicate calculus". These are deep mathematical topics. You don't need to learn it all, just the basics.

You should also learn about "short circuit evaluation". Because of this, the order of the expressions is important to exactly duplicate your original logic. While B || !A is logically equivalent, using this as the condition will execute "action C" when B is true regardless of the value of A.

呃,这也让我很困惑,但是作为 学徒守则指出,我们肯定需要 do action C或者运行嵌套的 else块,因此代码可以简化为:

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

这就是我们如何打击三个案子:

  1. 在你的问题的逻辑中嵌套的 do action C要求 condition Acondition Btrue——在这个逻辑中,如果我们达到 if语句中的2项,那么我们知道 condition Atrue,因此我们需要评估的只是 condition Btrue
  2. 在你的问题的逻辑中,嵌套的 else-block 要求 condition Atrue,而 condition Bfalse——在这种逻辑中,我们能够到达 else-block 的唯一方法是,如果 condition Atrue,而 condition Bfalse
  3. 你的问题逻辑中的外部 else块要求 condition Afalse——在这个逻辑中,如果 condition A是假的,我们也是 do action C

编码的道具-学徒在这里纠正我。我建议接受 他的回答,因为他没有编辑正确地呈现它:/

解决这类问题的第一步总是制作一个逻辑表。

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

一旦你摆好了桌子,解决方案就清楚了。

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

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

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

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

如果您不熟悉语法,每个模式都由 | 表示,后面跟着要与(a,b)匹配的值,下划线用作通配符,表示“任何其他值”。因为除了操作 c 之外,我们还需要做其他事情的唯一情况是当 a 为 true,b 为 false 时,我们将这些值显式地声明为第一个模式(true,false) ,然后执行在这种情况下应该执行的任何操作。在所有其他情况下,我们使用“通配符”模式并执行操作 c。

问题陈述:

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

描述 暗示: A暗示 B,一个相当于 !A || B的逻辑命题(如其他答案中提到的) :

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


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

尽管已经有了很好的答案,但我认为这种方法对于布尔代数的新手来说可能更直观,而不是评估一个真值表。

首先要做的是查看,在什么条件下要执行 C。这就是 (a & b)。也是当 !a。 所以你有 (a & b) | !a

如果你想最小化,你可以继续,就像“正常”的算术一样,你可以乘出。

(a & b) | !a = (a | !a) & (b | !a). 啊!A 总是为真,因此可以将其删除,这样就得到了最小化的结果: b | !a。 如果顺序有所不同,因为您想要检查 b 只有当!A 为真(例如当!A 是一个空指针检查,b 是一个对指针的操作,就像@Lord Farquaad 在他的评论中指出的那样) ,你可能需要切换这两个。

另一种情况(/* ... */)将始终在没有执行 c 时执行,所以我们可以将其放在 else 情况中。

同样值得一提的是,无论采用哪种方式,将操作 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.
}

这样,您还可以使用更多的操作数来最小化项,这会使真值表变得很难看。另一个好的方法是卡诺地图。但我现在不想再深究了。

我将把 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。 有一些方法来证明这个问题,如真值表,卡诺地图等。

所以在基于 C 的语言中,你可以这样使用:

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

附注: 卡诺地图也用于更复杂的一系列条件。 这是一种简化布尔代数表达式的方法。

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

使用标志也可以解决这个问题

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