我一直在研究Ruby Koans,并将其发送到about_triangle_project.rb,在其中您需要编写方法三角形的代码。
这些项目的代码可在此处找到:
https://github.com/edgecase/ruby_koans/blob/master/koans/about_triangle_project.rb
https://github.com/edgecase/ruby_koans/blob/master/koans/triangle.rb
在triangle.rb中,我创建了以下方法:
def triangle(a, b, c)
if ((a == b) && (a == c) && (b == c))
return :equilateral
elsif ((a == b) || (a == c) || (b == c))
return :isosceles
else
return :scalene
end
end
我从阅读克里斯·派恩的“学会计划”中知道,总有不止一种方法可以做。虽然上面的代码有效,但我不禁想到有一种更优雅的方式。是否有人愿意提出他们如何使这种方法更有效和紧凑的想法?
我很好奇的另一件事是,为了确定等边三角形,我无法创造(a == b == c)的条件。它是等边三角形的证明,但Ruby讨厌语法。对于为什么会有这么简单的解释吗?
答案 0 :(得分:55)
有一个简单的解释为什么:
Ruby中的 ==
是一个执行特定功能的运算符。运营商有规则来确定他们应用的顺序 - 例如,a + 2 == 3
在等式检查之前评估添加。但是一次只评估一个操作员。将两个相等性检查彼此相邻是没有意义的,因为相等性检查的结果为true
或false
。有些语言允许这样做,但它仍然无法正常工作,因为如果true == c
和a
相等,那么您将评估b
,即使a = = = b == c用数学术语表示。
至于更优雅的解决方案:
case [a,b,c].uniq.size
when 1 then :equilateral
when 2 then :isosceles
else :scalene
end
或者,甚至更简洁(但不太可读):
[:equilateral, :isosceles, :scalene].fetch([a,b,c].uniq.size - 1)
答案 1 :(得分:11)
另一种方法:
def triangle(a, b, c)
a, b, c = [a, b, c].sort
raise TriangleError if a <= 0 or a + b <= c
return :equilateral if a == c
return :isosceles if a == b or b == c
return :scalene
end
答案 2 :(得分:6)
def triangle(a, b, c)
if a == b && a == c # transitivity => only 2 checks are necessary
:equilateral
elsif a == b || a == c || b == c # == operator has the highest priority
:isosceles
else
:scalene # no need for return keyword
end
end
答案 3 :(得分:5)
我借用了Chuck的酷炫uniq.size技术并将其用于oo解决方案。最初我只想提取参数验证作为保护条款以维护单一责任原则,但由于两种方法都在相同的数据上运行,我认为它们属于一个对象。
# for compatibility with the tests
def triangle(a, b, c)
t = Triangle.new(a, b, c)
return t.type
end
class Triangle
def initialize(a, b, c)
@sides = [a, b, c].sort
guard_against_invalid_lengths
end
def type
case @sides.uniq.size
when 1 then :equilateral
when 2 then :isosceles
else :scalene
end
end
private
def guard_against_invalid_lengths
if @sides.any? { |x| x <= 0 }
raise TriangleError, "Sides must be greater than 0"
end
if @sides[0] + @sides[1] <= @sides[2]
raise TriangleError, "Not valid triangle lengths"
end
end
end
答案 4 :(得分:5)
class TriangleError < StandardError
end
def triangle(a, b, c)
sides = [a,b,c].sort
raise TriangleError if sides.first <= 0 || sides[2] >= sides[1] + sides[0]
return :equilateral if sides.uniq.length == 1
return :isosceles if sides.uniq.length == 2
:scalene
end
答案 5 :(得分:3)
这是我的解决方案:
def triangle(a, b, c)
sides = [a, b, c].sort
raise TriangleError, "Invalid side #{sides[0]}" unless sides[0] > 0
raise TriangleError, "Impossible triangle" if sides[0] + sides[1] <= sides[2]
return [:scalene, :isosceles, :equilateral][ 3 - sides.uniq.size ]
end
答案 6 :(得分:2)
嗯..我不知道uniq
- 所以来自smalltalk(很久以前)我用过:
require 'set'
def triangle(a, b, c)
case [a, b, c].to_set.count
when 1 then :equilateral
when 2 then :isosceles
else :scalene
end
end
答案 7 :(得分:2)
来自matlab世界,我习惯于数组函数&#39;任何&#39;并且&#39;所有&#39;,并且很高兴能够在Ruby中找到它们。所以:
def triangle(a, b, c)
eqs = [a==b, a==c, b==c]
eqs.all?? :equilateral : eqs.any?? :isosceles : :scalene
end
根据可读性,计算时间......(红宝石noob),不知道这是否是最佳的。
答案 8 :(得分:1)
这是我的解决方案:
def triangle(a, b, c)
return :equilateral if a == b and b == c
return :isosceles if ( a == b or b == c or a == c )
return :scalene
end