我的问题是:
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
是否可以只编写一次而不是编写两次动作C的代码?
如何简化呢?
我的问题是:
if (/* condition A */)
{
if(/* condition B */)
{
/* do action C */
}
else
/* ... */
}
else
{
/* do action C */
}
是否可以只编写一次而不是编写两次动作C的代码?
如何简化呢?
Answers:
解决此类问题的第一步始终是创建逻辑表。
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
}
请注意,这种逻辑虽然较短,但对于将来的程序员而言可能很难维护。
B
有副作用,逻辑表必须考虑到这一点。
A && !B
情况是“无操作”:!(A && !B)
等效于!A || B
这意味着您可以这样做if (!A || B) { /* do action C */ }
并避免出现空块。
if (A && !B)
将来的程序员确实很难维护,那么实际上没有任何帮助。
您有两种选择:
编写一个执行“动作C”的函数。
重新排列逻辑,以使您没有那么多的嵌套if语句。问自己,什么情况导致“动作C”发生。在我看来,它发生在“条件B”为真或“条件A”为假时。我们可以将其写为“ NOT A OR B”。将其转换为C代码,我们得到
if (!A || B) {
action C
} else {
...
}
要了解有关此类表达式的更多信息,建议使用谷歌搜索“布尔代数”,“谓词逻辑”和“谓词演算”。这些是深刻的数学主题。您不需要学习所有内容,而只是基础知识。
您还应该了解“短路评估”。因此,表达式的顺序对于精确复制原始逻辑很重要。尽管B || !A
在逻辑上是等效的,但使用B
true 作为条件将与条件无关地执行“动作C” A
。
...
是。如果什么都不做(即“如果满足这些条件,则执行C;否则,不执行任何操作”),则这显然是一种更好的解决方案,因为那时else
可以简单地将语句完全排除在外。
您可以像这样简化语句:
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
}
if (!A || B)
B || !A
将导致以true
仅当B
是true
,实际上并没有检查A
,由于短路
A
和B
代表。
问题陈述:
如果条件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 */
}
inline
为C constexpr
以及C ++?
gh,这也让我感到震惊,但是正如Code-Apprentice所指出的,我们保证需要do action C
或运行nested- else
block,因此可以将代码简化为:
if (not condition A or condition B) {
do action C
} else {
...
}
这是我们处理3种情况的方式:
do action C
在你的问题的逻辑要求condition A
,并condition B
为true
-在这样的逻辑,如果我们达到2 次的术语if
语句来那么我们就知道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
B
因此只有在!A
为假时才进行评估。因此,两者都必须失败才能执行else
语句。
!A || B
当!A
和B
均为假时,也恰好为假。因此,执行A
时为true else
。无需重新评估A
。
即使已经有了好的答案,我认为对于刚接触布尔代数然后评估真值表的人来说,这种方法可能更加直观。
你想要做的第一件事是看,在什么条件下要执行C.这是时的情况(a & b)
。也当!a
。所以你有(a & b) | !a
。
如果要最小化,可以继续。就像在“常规”算术中一样,您可以相乘。
(a & b) | !a = (a | !a) & (b | !a)
。一个| !a始终是正确的,因此您可以将其删除,从而使结果最小化b | !a
。如果顺序有所不同,因为仅当!a为真时才想检查b(例如,当!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.
}
这样,您还可以使用更多操作数来最小化术语,而事实表会很快使它们变得丑陋。另一个好的方法是卡诺地图。但是我现在不会更深入地介绍这一点。
为了使代码看起来更像文本,请使用布尔标志。如果逻辑特别不清楚,请添加注释。
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
{
...
}
我将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
最后一次反转