我的问题是:
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
是否可以只编写一次C代码而不是两次?
如何简化?
答案 0 :(得分:399)
这些问题的第一步始终是制作逻辑表。
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
}
请注意,这种逻辑虽然较短,但对于未来的程序员来说可能难以维护。
答案 1 :(得分:65)
您有两种选择:
编写执行“动作C”的功能。
重新排列逻辑,以便您没有这么多嵌套的if语句。问问自己什么条件导致“行动C”发生。它看起来像是在“条件B”为真或“条件A”为假时发生。我们可以把它写成“NOT A OR B”。将其转换为C代码,我们得到
if (!A || B) {
action C
} else {
...
}
要了解有关这些表达式的更多信息,我建议谷歌搜索“布尔代数”,“谓词逻辑”和“谓词演算”。这些都是深刻的数学主题。您不需要全部学习,只需要了解基础知识。
您还应该了解“短路评估”。因此,表达式的顺序对于精确复制原始逻辑非常重要。虽然B || !A
在逻辑上是等效的,但是当B
为真时,无论A
的值如何,使用此条件将执行“操作C”。
答案 2 :(得分:15)
你可以简化这样的陈述:
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
}
答案 3 :(得分:14)
在具有模式匹配的语言中,您可以更直接地反映QuestionC答案中的真值表来表达解决方案。
match (a,b) with
| (true,false) -> ...
| _ -> action c
如果您不熟悉语法,则每个模式都由|表示接着是与(a,b)匹配的值,下划线用作通配符表示"任何其他值"。由于我们想要做除动作c之外的其他事情的唯一情况是当a为真且b为假时,我们明确地将这些值表示为第一个模式(true,false),然后在那种情况下做任何应该做的事情。在所有其他情况下,我们都会看到"通配符"模式并采取行动c。
答案 4 :(得分:10)
问题陈述:
如果条件A匹配,则需要匹配条件B才能执行操作C
描述 implication : A 暗示 B ,一个等同于!A || B
的逻辑命题(如其他所述)答复):
bool implies(bool p, bool q) { return !p || q; }
if (implies(/* condition A */,
/* condition B */))
{
/* do action C */
}
答案 5 :(得分:6)
呃,这也让我感到沮丧,但是pointed out by Code-Apprentice我们保证需要do action C
或运行嵌套的else
块,因此代码可以简化为:
if (not condition A or condition B) {
do action C
} else {
...
}
这就是我们如何应对这三种情况:
do action C
需要condition A
而condition B
需要true
- 在此逻辑中,如果我们达到2 nd 在if
语句中的sup> term,我们知道condition A
是true
因此我们需要评估的是condition B
是true
else
- 块需要condition A
为true
而condition B
为false
- 我们能做到的唯一方法如果else
为condition A
且true
为condition B
false
- 块将到达
else
- 块需要condition A
为false
- 如果condition A
为假,我们也do action C
< / LI>
醇>
支持Code-Apprentice的道具让我在这里理顺。我建议接受his answer,因为他没有编辑就正确地展示了它:/
答案 6 :(得分:6)
尽管已经有了很好的答案,但我认为这种方法对于那些刚接触布尔代数然后评估真值表的人来说可能更直观。
您要做的第一件事就是查看您要在哪些条件下执行C. (a & b)
就是这种情况。同样在!a
时。
所以你有(a & b) | !a
。
如果你想最小化你可以继续。就像在&#34;正常&#34;算术,你可以多出来。
(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.
}
通过这种方式,您还可以使用更多操作数来最小化术语,这些操作数很快会因真值表而变得难看。另一个好方法是卡诺图。但我现在不想深入研究这个问题。
答案 7 :(得分:6)
在逻辑概念中,您可以按照以下方式解决此问题:
f = a.b +!a
f =?
作为一个经过验证的问题,这会产生f = !a + b
。
有一些方法可以证明问题,例如真值表,Karnaugh Map等等。
因此,在基于C的语言中,您可以使用如下:
if(!a || b)
{
// Do action C
}
P.S。:Karnaugh Map也用于更复杂的一系列条件。 它是一种简化布尔代数表达式的方法。
答案 8 :(得分:4)
要使代码看起来更像文本,请使用布尔标志。如果逻辑特别模糊,请添加注释。
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
{
...
}
答案 9 :(得分:3)
if((A && B ) || !A)
{
//do C
}
else if(!B)
{
//...
}
答案 10 :(得分:2)
我会将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
时间
答案 11 :(得分:2)
使用标志也可以解决这个问题
int flag = 1;
if ( condition A ) {
flag = 2;
if( condition B ) {
flag = 3;
}
}
if(flag != 2) {
do action C
}