我的问题有两个方面:
我没有意识到我可以像这样嵌套多个条件。这看起来很糟糕。我想想我知道这里发生了什么,但真的可以解释一下这样的人我能真正理解这个概念吗?
由于我不太了解嵌套条件,我在重构上有点迷失,这个区域我开始时很弱。你们是否会如此善良地提出一些可能的重构解决方案和解释?这将极大地帮助我有限的理解。
def valid_triangle?(a, b, c, sum)
if a != 0 || b != 0 || c != 0
if a >= b
largest = a
sum += b
else largest = b
sum += a
end
if c > largest
sum += largest
largest = c
else sum += c
end
if sum > largest
return "true"
else return "false"
end
else return false
end
end
答案 0 :(得分:4)
你可以通过类似Ruby的方式来减少这种情况:
def valid_triangle?(*sides)
case (sides.length)
when 3
sides.sort!
sides[0] + sides[1] >= sides[2]
else
false
end
end
尽可能尝试将您的逻辑表达为对数据的一系列转换,它通常更容易理解。在这种情况下,将传入点视为一个数组并对它们进行排序,而不是为每个点设置特殊情况逻辑。这个特殊的案例代码总是很麻烦,难以测试,如果你犯了一个小错误就容易出现细微的失败。
值得注意的是,在Ruby中,您应该将if
语句格式化为:
if condition
# ...
elsif condition
# ...
else
# ...
end
在else
之后包含代码可能是有效的语法,但要查看它会让人感到困惑。您似乎正在针对largest == b
进行测试并犯了一个错误,无意中执行了一项任务,当真的是else
块的内容时,不是elusive
的条件。
可以轻松更新此代码以包含负长度测试,例如在您的逻辑中添加sides[0] > 0
。
此外,包含Ruby 隐式 return
,其中提供的最后一个值是从方法返回的值。 case
语句实际上传播了触发值的值,这使得传递信息变得非常方便。
答案 1 :(得分:1)
实际上,嵌套条件的概念与任何其他类型的条件的概念没有太大的不同。条件控制是否执行其中的所有代码。因此,如果将一个条件嵌套在另一个条件内,则外条件将控制是否执行内部条件。
some_var = 5
if some_var > 1
# Code here will be executed
if some_var > 10
# Code here will not be executed
end
end
if some_var > 10
# Code here will not be executed
# The following conditional won't be checked at all,
# because execution won't reach this point.
if some_var > 1
# This won't be executed.
end
end
# The execution point will immediately jump to here once
# the some_var > 10 condition is determined to be false.
至于重构代码,这里有很多东西可以改进。例如,嵌套条件通常可以而且应该避免。不是因为它们难以理解,而是因为通常有更多可读的替代方案。
例如,您的代码将整个方法封装在一个大的条件中,基本上说“除非这个条件为真,否则不执行此方法的其余部分”:
if a != 0 || b != 0 || c != 0
# ...
else
return false # Note: Statements are conventionally
# placed on the next line after else.
# Not on the same line.
end
这可以通过在方法开头包含一个条件来避免,如果条件为假,则立即返回:
return false unless a != 0 || b != 0 || c != 0
我注意到的另一件事是你在某些情况下返回字符串而不是布尔值:
if sum > largest
return "true"
else
return "false"
end
这不是一个好主意。而是返回一个实际的布尔值:
if sum > largest
return true
else
return false
end
事实上,这整个条件并不是那么有用。 sum > largest
已经在一个案例中评估为true而在另一个案例中评估为false,因此您可以:
return sum > largest
另外,为什么要将sum
作为参数传递?那不应该总是从零开始吗?您可以从方法签名中删除该语句,只需在方法体中将sum初始化为0:
sum = 0
现在让我们看看你的代码是什么样的:
def valid_triangle?(a, b, c)
return false unless a != 0 || b != 0 || c != 0
sum = 0
if a >= b
largest = a
sum += b
else
largest = b
sum += a
end
if c > largest
sum += largest
largest = c
else
sum += c
end
return sum > largest
end
看起来好多了。中间的代码仍然相当复杂。让我们暂时考虑一下......似乎你想把largest
设置为三边的最大值,然后将总和设置为剩余边的总和。使用数组排序非常容易:
sides = [a, b, c].sort
现在,sides
包含所有方面的排序数组。最后一个元素将是最大的...
largest = sides.last
......其他两方可用于查找总和:
sum = sides[0] + sides[1]
现在让我们看看我们在哪里:
def valid_triangle?(a, b, c)
return false unless a != 0 || b != 0 || c != 0
sides = [a, b, c].sort
largest = sides.last
sum = sides[0] + sides[2]
return sum > largest
end
尼斯!
通过更好地理解Ruby的一些内置方法,可以使这更简单。我不会详细介绍所有细节,但是这里我可能会编写这段代码:
def valid_triangle?(a, b, c)
sides = [a, b, c].sort
sides.all?{|s| s != 0} && sides.pop <= sides.reduce(:+)
end
这是如何工作的?让我分解一下。
首先,和以前一样,我们将所有边都收集到一个排序列表中,这样最小边是第一个元素,最大边是最后一个元素。这将使我们以后的计算变得更加容易。
sides = [a, b, c].sort
接下来,我们检查所有方面是否为非零。
sides.all?{|s| s != 0}
然后,我们检查最大的一侧是否至少与另一侧的总和一样小。我这样做是通过从排序列表中删除最大的一边,然后检查该值是否小于列表中其余两边的总和(使用sides.reduce(:+)
找到):
sides.pop <= sides.reduce(:+)
这两个条件的结果与&&
结合并从方法返回(Ruby自动返回方法中最后执行的语句,因此我们可以在这里省略return关键字。)
这是一个列表链接,指向我在此解决方案中使用的内置方法的文档。请检查文档中是否有任何您不理解的方法,以了解它们的工作原理:
答案 2 :(得分:0)
在不触及核心算法的情况下,您可以采取以下措施来改进方法结构。
def valid_triangle?(a, b, c, sum)
# terminate early if inputs are not in expected state
return false if [a,b,c].include? 0
if a >= b
largest = a
sum += b
else
largest = b
sum += a
end
# space to separate this from the previous if/else block
if c > largest
sum += largest
largest = c
else
sum += c
end
# be consistent on return type (string or boolean)
sum > largest
# ternary if can be used if return type is not a boolean
# strings are not recommended for true/false values though
# sum > largest ? "true" : "false"
end