Ruby Koans更优雅的解决方案';三角形.rb
我一直在研究Ruby Koans,并将其提交到about_triangle_project.rb,其中要求您为方法triangle编写代码 以下是这些项目的代码: 在triangle.rb中,我创建了以下方法:Ruby Koans更优雅的解决方案';三角形.rb,ruby,Ruby,我一直在研究Ruby Koans,并将其提交到about_triangle_project.rb,其中要求您为方法triangle编写代码 以下是这些项目的代码: 在triangle.rb中,我创建了以下方法: def triangle(a, b, c) if ((a == b) && (a == c) && (b == c)) return :equilateral elsif ((a == b) || (a == c) || (b == c
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
通过阅读Chris Pine的《学会编程》我知道,做事的方法总是不止一种。尽管上面的代码可以工作,但我还是忍不住认为有一种更优雅的方法可以做到这一点。有没有人愿意就如何使这种方法更有效、更紧凑提出自己的想法
另一件我很好奇的事情是,为什么为了确定一个等边三角形,我不能创建(a==b==c)的条件。这是等边三角形的证明,但Ruby讨厌这种语法。有一个简单的解释来解释为什么会这样吗?有一个简单的解释来解释为什么会这样:
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
Ruby中的=
是一个运算符,它执行特定的函数。运算符具有确定其应用顺序的规则-例如,a+2==3
在相等检查之前计算加法。但一次只计算一个运算符。将两个相等性检查放在一起是没有意义的,因为相等性检查的计算结果为true
或false
。有些语言允许这样做,但它仍然不能正常工作,因为如果a
和b
相等,那么您将计算true==c
,这显然不是真的,即使a==b==c在数学术语中也是如此
至于更优雅的解决方案:
case [a,b,c].uniq.size
when 1 then :equilateral
when 2 then :isosceles
else :scalene
end
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
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
或者,更简短(但可读性较差):
我借用了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
#与测试的兼容性
def三角板(a、b、c)
t=三角形。新的(a、b、c)
返回t.type
结束
阶级三角
def初始化(a、b、c)
@边=[a,b,c]。排序
防止无效长度
结束
def类型
case@sides.uniq.size
当1时,则为:等边
当2时,则为:等腰
其他:异丙苯
结束
结束
私有的
def防护装置防止长度无效
如果@sides.any?{| x | x另一种方法:
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
def三角形(a、b、c)
a、 b,c=[a,b,c].排序
如果aHmm..我不知道uniq
-所以来自smalltalk(很久以前),我使用:
以下是我的解决方案:
case [a,b,c].uniq.size
when 1 then :equilateral
when 2 then :isosceles
else :scalene
end
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
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
def三角形(a、b、c)
边=[a,b,c]。排序
提升三角形错误,“无效边#{sides[0]}”,除非边[0]>0
提高三角形错误,如果边[0]+边[1]则为“不可能的三角形”:
case [a,b,c].uniq.size
when 1 then :equilateral
when 2 then :isosceles
else :scalene
end
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
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
class TriangleError
来自matlab世界,我习惯于数组函数“any”和“all”,并且很高兴在Ruby中找到它们。因此:
def triangle(a, b, c)
eqs = [a==b, a==c, b==c]
eqs.all?? :equilateral : eqs.any?? :isosceles : :scalene
end
不过,就可读性和计算时间而言,不知道这是否是最优的…(ruby noob)。==
是一个接受值的运算符(如*
或/
)。它返回true
或false
。不引起混淆是非法的(例如,1==1==1
将计算为false
,因为它相当于(1==1==1
)。您可以通过使用:等边
:(a==b)和&(b==c)的可传递属性来节省一些代码。Python支持“a==b==c”语法(甚至“auniq.size
;这很优雅。有趣的是,你选择使用fetch
,如[…][…]uniq.size]
是有效的。@Phrogz:我一开始是这样写的,但它太难读了,就像人们经常取笑的那种Perl代码一样,所以我想fetch
至少接近我想读的东西。我想出了这个代码:[nil,:等边,:等腰,:scalene][[a,b,c].uniq.size]
但我认为你的更具可读性。很棒的东西,但请注意更简洁的解决方案中的两个打字错误(等腰和不等腰)。更改太少,无法编辑。谢谢你,glebm!(还有上面的答案。)这也是对about_triangle_项目_2.rb的测试部分的一个很好的回答。我复制了你的解决方案,它比我的机器代码版本优雅得多。+1巧妙地使用了排序,以避免不必要的比较。我必须将类TriangleError