(我复制/粘贴我在Codereview上发布的相同问题: https://codereview.stackexchange.com/questions/1747/good-practice-loop-and-if-statement)
我想知道最佳做法是什么:
版本A:
loop1
if condition1
code1
if condition2
code2
if condition3
code3
或者,版本B:
if condition1
loop1 with code1
if condition2
loop1 with code2
if condition3
loop1 with code3
我已经实现了版本B,因为它对我来说更具可读性,并且始终检查相同的条件似乎很荒谬。
但循环n次相同的阵列也可能被视为荒谬:)
从你正在考虑具有循环之外的条件的版本B的事实来看,我假设条件的真值不随阵列中的元素而变化。否则,你的问题没有意义。
结论
如果条件复杂使得它们相对于阵列的大小在评估中花费了很多时间,则版本B更快。如果是相反的方式,则版本A更快。
在这种情况下哪个更快应该与你应该采取的策略重合,因为在复杂结构中嵌入简单结构而不是在简单结构中嵌入复杂结构更容易理解。
说明
当条件相对于数组的大小足够简单时,迭代的成本超过评估条件的成本。如下面用ruby所述,版本B较慢。
$a = (1..10000)
def versionA
$a.each do
nil if true
nil if false
nil if true
end
end
def versionB
$a.each {nil} if true
$a.each {nil} if false
$a.each {nil} if true
end
require 'benchmark'
n = 10000
Benchmark.bmbm do|b|
b.report('A'){n.times{versionA}}
b.report('B'){n.times{versionB}}
end
Rehearsal -------------------------------------
A 7.270000 0.010000 7.280000 ( 7.277896)
B 13.510000 0.010000 13.520000 ( 13.515172)
--------------------------- total: 20.800000sec
user system total real
A 7.200000 0.020000 7.220000 ( 7.219590)
B 13.580000 0.000000 13.580000 ( 13.605983)
另一方面,如果相对于阵列上的迭代来评估条件成本更高,那么前者的效果将变得比后者更重要,并且速度将是另一种方式。
$a = (1..100)
def versionA
$a.each do
nil if (1..10).each{nil} && true
nil if (1..10).each{nil} && false
nil if (1..10).each{nil} && true
end
end
def versionB
$a.each {nil} if (1..10).each{nil} && true
$a.each {nil} if (1..10).each{nil} && false
$a.each {nil} if (1..10).each{nil} && true
end
require 'benchmark'
n = 10000
Benchmark.bmbm do|b|
b.report('A'){n.times{versionA}}
b.report('B'){n.times{versionB}}
end
Rehearsal -------------------------------------
A 2.860000 0.000000 2.860000 ( 2.862344)
B 0.160000 0.000000 0.160000 ( 0.169304)
---------------------------- total: 3.020000sec
user system total real
A 2.830000 0.000000 2.830000 ( 2.826170)
B 0.170000 0.000000 0.170000 ( 0.168738)
因为你可能通常希望版本B更加明显
if condition1
loop1 with code1
if condition2
loop2 with code2
if condition3
loop3 with code3
这不能从A快速轻松地重构。
编辑:但是,如果循环“条件”由它的主体动态驱动,则应该使用A.需要更多关于代码语义的信息。
好吧,我认为答案比看上去更合格。大多数编码实践都建议保持较小的代码块,因此从这个角度来看,它实际上归结为“整个块有多大”?但我会根据代码的意图考虑这一点。例如:
foreach (widgets)
if (widget is red) put in left bin
if (widget is blue) put in center bin
if (widget is green) put in right bin
VS:
if (making widgets red)
foreach (widgets) put in left bin
if (making widgets blue)
foreach (widgets) put in center bin
if (making widgets green)
foreach (widgets) put in right bin
每个结构都讲述了一个关于你的意图的不同故事。在第一种情况下,我们迭代小部件并对每个小部件做出决策,而在后一种情况下,我们在展开的循环中迭代决策并对小部件进行更改。这当然对else-if案例更有意义,但总的来说,如果你可以轻松地对一段代码做一个声明(例如,在这个循环中,我按颜色排序小部件)而不必写一个段落,那就是最易理解的代码,这是最佳实践的目标。
当然,性能也是一个问题。我想性能和最佳实践是不安的朋友。如果您正在访问数据库以进行迭代以获取每一行,或者如果迭代超过数千个条目,则有时需要编写面向意图较少的代码,以将最慢的操作减少到最小。这不是第一个考虑因素,但编写有效的代码需要人们从各个角度看问题并做出妥协,因此规则不是那么难和快。
在方案A中,您将对循环的每次重复进行三次if检查。在方案B中,您只有三个if-check总计。在时间复杂度方面,第二个版本要好得多。
如果你必须负担两个条件呢?
如果condition1和condition2都被验证会发生什么?
我认为条件更好