如果条件A匹配,则需要匹配条件B以执行动作C.

sta*_*15h 147 language-agnostic boolean-logic if-statement conditional-statements

我的问题是:

if (/* condition A */)
{
    if(/* condition B */)
      {
         /* do action C */
      }
    else
      /* ... */
}
else
{
   /* do action C */
}
Run Code Online (Sandbox Code Playgroud)

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

如何简化?

Que*_*onC 399

这些问题的第一步始终是制作逻辑表.

A | B | Result
-------------------
T | T | do action C
T | F | ...
F | T | do action C
F | F | do action C
Run Code Online (Sandbox Code Playgroud)

一旦你制作了表格,解决方案就很明确了.

if (A && !B) {
  ...
}
else {
  do action C
}
Run Code Online (Sandbox Code Playgroud)

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

  • @Yakk我的答案没有解决副作用有两个原因.首先,该解决方案确实(巧合地)具有正确的副作用行为.其次,更重要的是,具有副作用的A和B将是糟糕的代码,关于该边缘情况的讨论将从根本上分析布尔逻辑的问题. (79认同)
  • 如果`if(A &&!B)`对于未来的程序员来说真的很难维护,那么真的没有帮助他们. (54认同)
  • 也许值得注意,如果'A &&!B`案例是无操作:`!(A &&!B)`相当于`!A || B`这意味着你可以做`if(!A || B){/*做动作C*/}`并避免空块. (52认同)
  • 我真的很喜欢你展示真相表,以帮助OP了解如何自己开发.你能进一步解释一下如何从真值表中得到布尔表达式吗?对于刚接触编程和布尔逻辑的人来说,这可能一点也不清楚. (35认同)
  • 如果评估"B"有副作用,逻辑表必须考虑到这一点. (14认同)
  • 哦,来吧,有人至少提到[卡诺图](https://en.wikipedia.org/wiki/Karnaugh_map). (9认同)
  • 我没有看到这比原始代码更难维护.如果有的话,它更容易*因为*它更短.即使您在面对不熟悉的条件表达式时必须制作真值表,简洁意味着您不会重复自己(干). (7认同)
  • 你是说我不是人,@ lucidbrot? (6认同)
  • @KRyan为了完整起见,我想补充一点,你使用了De Morgan定律进行转换(可能有助于理解该形式的布尔表达式一般如何转换).https://en.wikipedia.org/wiki/De_Morgan%27s_laws (6认同)
  • @CodyGray根据A和B的命名及其目的,代码可能会令人困惑,因为它不遵循人类的方式来思考它并合并可能看起来与人类不同的情况. (3认同)
  • 在这种情况下,重命名的东西,所以它确实有意义.正确使用您的重构工具! (2认同)
  • 感谢逻辑表的想法.我总是在这样的艰苦条件下挣扎,猜测这将有助于将来 (2认同)

Cod*_*ice 65

您有两种选择:

  1. 编写执行"动作C"的功能.

  2. 重新排列逻辑,以便您没有这么多嵌套的if语句.问问自己什么条件导致"行动C"发生.它看起来像是在"条件B"为真或"条件A"为假时发生.我们可以把它写成"NOT A OR B".将其转换为C代码,我们得到

    if (!A || B) {
        action C
    } else {
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

为了更多地了解这些表达式,我建议谷歌搜索"布尔代数","谓词逻辑"和"谓词演算".这些都是深刻的数学主题.您不需要全部学习,只需要了解基础知识.

您还应该了解"短路评估".因此,表达式的顺序对于精确复制原始逻辑非常重要.虽然B || !A在逻辑上是等价的,但是当条件B为真时,使用它作为条件将执行"action C",而不管其值是多少A.

  • @Yakk参见deMorgan的法律. (15认同)
  • @ Starf15h另外还有一个重要的区别:执行"动作C"的地方.这种差异使我们的两种解决方案完全相同 我建议你谷歌"deMorgan的法律",它可以帮助你了解这里发生了什么. (6认同)
  • 这两种解决方案完全相同,但可能存在实际差异 - 取决于究竟是什么```is_.如果它什么都没有(即"如果满足这些条件则执行C;否则什么都不做"),那么这显然是优越的解决方案,因为"else"语句可以简单地完全省略. (5认同)

Cin*_*out 15

您可以像这样简化语句:

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

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

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

  • 或者更简单地说`if(!A || B)` (7认同)
  • 从逻辑上讲,((A && B)||!A)相当于(B ||!A) (2认同)

Aar*_*ach 14

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

match (a,b) with
| (true,false) -> ...
| _ -> action c
Run Code Online (Sandbox Code Playgroud)

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


jam*_*lin 10

问题陈述:

如果条件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 */
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*Mee 6

呃,这也让我感到高兴,但正如Code-Apprentice指出的那样,我们保证需要do action C或运行嵌套else块,因此代码可以简化为:

if (not condition A or condition B) {
    do action C
} else {
    ...
}
Run Code Online (Sandbox Code Playgroud)

这就是我们如何击中3个案例:

  1. 嵌套do action C在你的问题的逻辑要求condition A,并condition Btrue-在这样的逻辑,如果我们达到2 的术语if语句来那么我们就知道condition Atrue这样,所有我们需要评估的是,condition Btrue
  2. 嵌套else在你的问题的逻辑-阻塞要求condition Atruecondition Bfalse-我们能够达到的唯一方法else在这种逻辑-阻塞是,如果condition Atruecondition Bfalse
  3. else你的问题的逻辑要求-块condition Afalse-在这样的逻辑,如果condition A是假的,我们也do action C

Code-Apprentice的道具让我在这里理顺.我建议接受他的答案,因为他没有编辑就正确地提出了答案:/

  • 请注意,不需要再次评估"条件A".在C++中,我们有被排除在中的法则.如果"非条件A"为假,则"条件A"必然为真. (2认同)

dee*_*etz 6

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

你要做的第一件事就是看,你想在哪些条件下执行C.这就是这种情况(a & b).当时!a.所以你有(a & b) | !a.

如果你想最小化你可以继续下去.就像在"普通"算术中一样,你可以相乘.

(a & b) | !a = (a | !a) & (b | !a).a | !a总是如此,所以你可以把它划掉,这样你就可以得到最小化的结果:b | !a.如果顺序有所不同,因为你只想检查b!a是否为真(例如,当a是空指针检查而b是对指针的操作,如@LordFarquaad在他的评论中指出的那样),你可能会想要切换两个.

另一种情况(/*...*/)将在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.
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您还可以使用更多操作数来最小化术语,这些操作数很快会因真值表而变得难看 另一个好方法是卡诺图.但我现在不会深入研究这个问题.


Siy*_*mdi 6

在逻辑概念中,您可以按如下方式解决此问题:

f = ab +!a
f =?

作为一个经过验证的问题,这导致了f = !a + b.有一些方法可以证明问题,如真值表,卡诺图等.

所以在基于C语言中你可以使用如下:

if(!a || b)
{
   // Do action C
}
Run Code Online (Sandbox Code Playgroud)

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