我已经分开了一项测试,以确定两个计划项目是否重叠,因为它的不可读性。
是否有任何应用程序可以帮助简化逻辑陈述?
示例:(最初是一个错误的例子,但是暴露了我要求的原因)
if (x < y && y < z && x < z)
可以缩减为
if (x < y && y < z)
我的代码是:
return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.Start && shift2.End >= shift.Start)
我希望能够更简单,我相信这是可能的,只是不确定如何。
看到这确实是语言不可知的,即使转换到不同的脚本来寻找可能性也会很好,例如,不需要它在C#中。
答案 0 :(得分:7)
杀死重复的逻辑,你将一石二鸟。你会得到干,你会得到一个功能名称(富人的评论):
class Shift:
def encompasses(other_shift)
self.start <= other_shift.start && self.end >= other_shift.end
...
return shift1.encompasses(shift2) || shift2.encompasses(shift1)
答案 1 :(得分:6)
对这些变化非常非常小心。它们看起来很简单,而且布尔逻辑(和DeMorgan的定律)并不难理解,但是当你看到个别情况时,往往会有潜在的陷阱:
例如:if(x&lt; y&amp;&amp; y&lt; z)可以简化为if(x&lt; z)
这是不正确的,如果(x < z)
,y
可能仍然大于z
。该状态不会通过原始测试。
答案 2 :(得分:4)
虽然x < y && y < z
暗示x < z
(&lt;是传递性的),但反之则不然,因此表达式不相等。实际上,如果将y
定义为Integer y = null
,则前者甚至可能导致Java中的NPE或SQL中的UNKNOWN。
答案 3 :(得分:3)
是否有任何应用程序可以帮助简化逻辑陈述?
我没有看到有人解决这个问题的这一部分,所以我会采取刺,看看会发生什么讨论。
有一些使用布尔逻辑的技术。回到我的大学时代(BSEE),我们使用了Karnaugh maps。基本上,您可以采用非常复杂的任意真值表并确定正确和优化的逻辑表达式。我们用它来减少电路中逻辑门的数量,这类似于简化复杂的if
语句。
优点:
缺点:
最终,最关键的是真值表/逻辑表达式的正确性。错误意味着您的程序无法正常工作。如果您没有正确理解需要实现的逻辑的定义,那么任何应用程序或设计技术都无济于事。
在我看来,很少有现实问题足够复杂,无法真正从这种技术中受益,但确实存在。
答案 4 :(得分:2)
这样做时你需要非常小心...例如,你给出的例子不是真的......如果x = 1,y = 2,z = 2,那么x&lt; y =真,x < z =真,但y < z =假。对于这种类型的推理,你真的想在这些情况下寻求代码可读性,而不用担心你能得到的最有效的代码。
答案 5 :(得分:2)
当谈到复杂的逻辑语句时,通常最好以可读的方式格式化代码而不是尝试一些过早的优化(所有邪恶的根源等)。
例如:
return (shift.Start <= shift2.Start && shift.End >= shift2.End) || (shift2.Start <= shift.StartTime && shift2.End >= shift.Start)
为了便于阅读和维护,可以重构为:
bool bRetVal = false;
bRetVal = ( ( (shift.Start <= shift2.Start)
&& (shift.End >= shift2.End))
|| ( (shift2.Start <= shift.StartTime)
&& (shift2.End >= shift.Start)))
return bRetVal;
大多数地方都维护着一个编码标准,它为大型逻辑块定义了类似的内容。我宁愿保留一些额外的代码行,这些代码可以读取和理解,而不是一行的怪物。
答案 6 :(得分:1)
有时你可以包装诸如
之类的陈述shift.Start&lt; = shift2.Start&amp;&amp; shift.End&gt; = shift2.End
进入布尔函数以使其更具可读性,例如:
功能ShiftWithinValidRange(这里有可怕的名字,但你明白了)
{
返回(shift.Start&lt; = shift2.Start&amp;&amp; shift.End&gt; = shift2.End);
}
答案 7 :(得分:1)
假设Start和StartTime实际上应该是同一个字段,那么你的条件归结为
(a <= b && c >= d) || (b <= a && d >= c)
我们可以把它变成
(a <= b && d <= c) || (b <= a && c <= d)
但这仍然看起来不像它简化了很多。
答案 8 :(得分:0)
这不仅危险,而且通常会导致难以维护代码。分解为特定步骤时,布尔逻辑更容易理解。压缩逻辑通常会导致更难理解逻辑。
即。在您的示例中,我们为什么要检查x < z
,我们真正想知道的是x < y && y < z
?
最简单的解决方案往往是最好的解决方案。从长远来看,将你的逻辑压缩成“更酷”但代码不太可读的代码并不好。
答案 9 :(得分:0)
我没有一个通用的解决方案,但如果我使用Lisp语法,对我来说看起来要简单得多:
(and (< x y)
(< y z)
(< x z))
然后注意前两个条款:
(and (< x y)
(< y z))
可以组合成:
(and (< x y z))
所以完整的表达式现在看起来像:
(and (< x y z)
(< x z))
现在很明显,第二个是多余的,所以它归结为:
(and (< x y z))
或简单地说:
(< x y z)
在C语法中是:
(x < y && y < z)
答案 10 :(得分:0)
我认为Wayne Conrad的答案是正确的,但仅出于娱乐目的,这是另一种说法(我认为):
(long) shift.Start.CompareTo(shift2.Start) * (long) shift.End.CompareTo(shift2.End) <= 0
这实际上更快吗?我不知道。这当然更难阅读。