我的问题是:
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在逻辑上是等效的,但使用Btrue 作为条件将与条件无关地执行“动作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- elseblock,因此可以将代码简化为:
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是trueelse在你的问题的逻辑-阻塞要求condition A是true和condition B是false-我们能够达到的唯一方法else在这种逻辑-阻塞是,如果condition A是true和condition B人falseelse您问题逻辑中的外层块必须condition A为false-在此逻辑中,如果condition A为假,我们也do action CB因此只有在!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最后一次反转