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

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

提问人:starf15h 提问时间:7/20/2017 最后编辑:Siyavash Hamdistarf15h 更新时间:10/26/2021 访问量:14335

问:

我的问题是:

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

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

如何简化它?

if-statement 语言无关 条件语句 逻辑

评论

57赞 CinCout 7/20/2017
将“操作 C”的代码放在函数中?
26赞 YSC 7/20/2017
这很遗憾,这与HNQ的C++问题无关:/
2赞 starf15h 7/21/2017
谢谢大家对我的帮助!一开始,我只想确保一切正常,所以我使用了嵌套的 if。这是因为这是我猜到的最简单的方法。下次提问后我会努力多加努力。祝大家有美好的一天:)
13赞 Code-Apprentice 7/21/2017
这是一个非常好的策略:先写出有效的代码,然后再担心以后如何让它变得优雅和高效。
3赞 CinCout 7/22/2017
@Tim我确实把它作为答案贴了出来。顺便说一句,看到那里的选票减少是可悲的。

答:

15赞 CinCout 7/20/2017 #1

您可以像这样简化语句:

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
}

评论

7赞 Tas 7/20/2017
或者更简单地说if (!A || B)
2赞 Code-Apprentice 7/20/2017
从逻辑上讲,((A&&B) || !A) 等价于 (B || !A)
0赞 CinCout 7/20/2017
@Code-Apprentice 仅当 是 时才会导致 ,而没有实际检查由于短路B || !AtrueBtrueA
1赞 Code-Apprentice 7/20/2017
@CinCout 好点子。虽然从理论布尔逻辑的角度来看,我的陈述仍然是正确的,但我没有考虑到短路布尔运算符的实用性。幸运的是,我自己的答案有正确的顺序。
1赞 Code-Apprentice 7/21/2017
所以从逻辑的角度来看,顺序并不重要。但是,从维护和可读性的角度来看,根据确切的内容和代表,可能会有巨大的差异。AB
65赞 Code-Apprentice 7/20/2017 #2

您有两种选择:

  1. 编写一个执行“操作 C”的函数。

  2. 重新排列逻辑,使没有那么多嵌套的 if 语句。问问自己,什么条件导致“动作C”发生。在我看来,当“条件 B”为真或“条件 A”为假时,就会发生这种情况。我们可以将其写为“NOT A OR B”。将其转换为 C 代码,我们得到

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

要了解更多关于这类表达式的信息,我建议在谷歌上搜索“布尔代数”、“谓词逻辑”和“谓词演算”。这些都是深奥的数学主题。你不需要学习所有的东西,只需要学习基础知识。

您还应该了解“短路评估”。因此,表达式的顺序对于完全复制原始逻辑非常重要。虽然在逻辑上是等价的,但使用此作为条件将在 true 时执行“操作 C”,而不管 的值如何。B || !ABA

评论

15赞 Code-Apprentice 7/20/2017
@Yakk 参见德摩根定律。
0赞 starf15h 7/20/2017
@Code-学徒 请原谅我糟糕的逻辑思维。我想问一下(!一个 ||B) 和 (A & !B).似乎两者都可以解决我的问题。我的意思是你和QuestionC的方法。
6赞 Code-Apprentice 7/20/2017
@Starf15h 还有一个关键的区别:“动作C”的执行位置。这种差异使我们的两个解决方案完全相同。我建议你在谷歌上搜索“德摩根定律”,这应该可以帮助您了解这里发生的事情。
5赞 Janus Bahs Jacquet 7/20/2017
这两种解决方案是完全等效的,但根据究竟是什么可能会有实际的差异。如果它什么都不是(即,“如果满足这些条件,则执行 C;否则什么都不做“),那么这显然是更好的解决方案,因为该语句可以完全省略。else
1赞 Michael 7/20/2017
此外,根据 A 和 B 的名称,这种安排可能比问题 C 的安排对人类来说更具可读性或更不易读性。
6赞 Jonathan Mee 7/20/2017 #3

呃,这也绊倒了我,但正如 Code-Apprentice 所指出的,我们保证需要或运行嵌套块,因此代码可以简化为:do action Celse

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

这就是我们处理 3 种情况的方式:

  1. 嵌套在问题逻辑中 required 和 to be -- 在这个逻辑中,如果我们到达 -statement 中的第二个项,那么我们知道 因此我们需要评估的只是do action Ccondition Acondition Btrueifcondition Atruecondition Btrue
  2. 问题逻辑中嵌套的 -block 需要 be 和 to be -- 在这个逻辑中,我们到达 -block 的唯一方法是 if were 和 wereelsecondition Atruecondition Bfalseelsecondition Atruecondition Bfalse
  3. 你的问题逻辑中的外部块必须是 -- 在这个逻辑中,如果 is false,我们也elsecondition Afalsecondition Ado action C

感谢 Code-Apprentice 在这里理顺了我。我建议接受他的答案,因为他在没有编辑的情况下正确地呈现了它:/

评论

2赞 Code-Apprentice 7/20/2017
请注意,“条件 A”不需要再次评估。在C++中,我们有排除中间定律。如果“不是条件 A”为假,则“条件 A”必然为真。
1赞 Code-Apprentice 7/20/2017
由于短路评估,只有在为false时才会进行评估。因此,两者都必须失败才能执行语句。B!Aelse
0赞 Code-Apprentice 7/20/2017
即使没有短路评估也是错误的,当两者都是错误的。因此,在执行时为 true。无需重新评估。!A || B!ABAelseA
0赞 Jonathan Mee 7/20/2017
@Code-学徒 太臭了,观察力很好,我已经纠正了我的答案,但建议接受你的答案。我只是想解释你已经提出的问题。
0赞 Code-Apprentice 7/20/2017
我希望我能再给你一票来解释每个案例。
401赞 QuestionC 7/20/2017 #4

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

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
}

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

评论

35赞 Code-Apprentice 7/20/2017
我真的很喜欢你展示真相表来帮助 OP 了解如何自己开发它。您能否更进一步解释一下如何从真值表中获取布尔表达式?对于刚接触编程和布尔逻辑的人来说,这可能根本不清楚。
14赞 Yakk - Adam Nevraumont 7/20/2017
如果评估有副作用,逻辑表必须考虑到这一点。B
79赞 QuestionC 7/20/2017
@Yakk 我的回答没有解决副作用,原因有两个。首先,该解决方案确实(巧合地)具有正确的副作用行为。其次,更重要的是,A和B具有副作用将是糟糕的代码,而关于该边缘情况的讨论将分散对布尔逻辑基本问题的注意力。
52赞 KRyan 7/21/2017
也许值得一提的是,如果情况是 no-op:,则等同于这意味着您可以执行并避免空块。A && !B!(A && !B)!A || Bif (!A || B) { /* do action C */ }
55赞 Ray 7/21/2017
如果未来的程序员真的很难维护,那么真的没有帮助他们。if (A && !B)
14赞 Aaron M. Eshbach 7/21/2017 #5

在具有模式匹配的语言中,您可以以更直接地反映问题 C 答案中的真值表的方式表达解决方案。

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

如果您不熟悉语法,则每个模式都由 |后跟与 (a,b) 匹配的值,下划线用作通配符表示“任何其他值”。由于我们想要执行操作 c 以外的唯一情况是 a 为 true 而 b 为 false,因此我们明确地将这些值声明为第一个模式 (true,false),然后执行在这种情况下应该执行的任何操作。在所有其他情况下,我们都会陷入“通配符”模式并执行操作 c。

10赞 jamesdlin 7/21/2017 #6

问题陈述:

如果条件 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 */
}

评论

0赞 einpoklum 7/22/2017
也许将其标记为 C 和 C++?inlineconstexpr
0赞 jamesdlin 7/23/2017
@einpoklum我没有深入其中的一些细节,因为这个问题并没有真正指定一种语言(但给出了一个类似 C 语法的例子),所以我给出了一个类似 C 语法的答案。就我个人而言,我会使用宏,这样就不会不必要地评估条件 B。
6赞 deetz 7/21/2017 #7

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

你要做的第一件事是看,你想在什么条件下执行C。当 .此外,当 . 所以你有.(a & b)!a(a & b) | !a

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

(a & b) | !a = (a | !a) & (b | !a). a | !a 始终为 true,因此您可以将其划掉,从而得到最小化的结果:。 如果顺序有所不同,因为您只想在 !a 为 true 时检查 b(例如,当 !a 是空指针检查,b 是指针上的操作时,就像@LordFarquaad在他的注释中指出的那样),您可能需要切换两者。b | !a

另一种情况 (/* ... */) 总是在 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.
}

这样,您还可以最小化具有更多操作数的术语,这在真值表中很快就会变得丑陋。另一个好方法是 Karnaugh 地图。但我现在不会更深入地讨论这个问题。

2赞 Dave Cousineau 7/23/2017 #8

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

摘录 C:

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

先反转先摆脱:ifelse

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

4赞 anatolyg 7/24/2017 #9

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

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
  {
  ...
  }
6赞 Siyavash Hamdi 7/26/2017 #10

在逻辑概念中,你可以按如下方式解决这个问题:

f = a.b + !a
f = ?

作为一个已验证的问题,这会导致 . 有一些方法可以证明问题,例如真值表、卡诺地图等。f = !a + b

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

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

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

3赞 Ali Faris 8/3/2017 #11
if((A && B ) || !A)
{
  //do C
}
else if(!B)
{
  //...
}
2赞 Spr k 8/4/2017 #12

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

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