Ruby Koans的triangle.rb更优雅的解决方案

eri*_*own 15 ruby

我一直在研究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
Run Code Online (Sandbox Code Playgroud)

我从阅读克里斯·派恩的"学会计划"中了解到,总有不止一种方法可以做.虽然上面的代码有效,但我不禁想到有一种更优雅的方式.是否有人愿意提出他们如何使这种方法更有效和紧凑的想法?

我很好奇的另一件事是,为了确定等边三角形,我无法创造(a == b == c)的条件.它是等边三角形的证明,但Ruby讨厌语法.有一个简单的解释,为什么这是?

Chu*_*uck 55

有一个简单的解释为什么:

==在Ruby中是一个执行特定功能的运算符.操作员有规则来确定他们应用的顺序 - 例如,a + 2 == 3在等式检查之前评估添加.但是一次只评估一个操作员.将两个相等性检查彼此相邻是没有意义的,因为相等性检查的计算结果为truefalse.有些语言允许这样做,但它仍然不工作的权利,因为那时你会评估true == c,如果ab是相等的,这显然是不正确的,即使一个== b ==下,在数学术语.

至于更优雅的解决方案:

case [a,b,c].uniq.size
when 1 then :equilateral
when 2 then :isosceles
else        :scalene
end
Run Code Online (Sandbox Code Playgroud)

或者,甚至更简洁(但不太可读):

[:equilateral, :isosceles, :scalene].fetch([a,b,c].uniq.size - 1)
Run Code Online (Sandbox Code Playgroud)

  • 'uniq.size`的+1; 那很优雅.有趣的是你选择使用`fetch`,因为`[...] [[...].uniq.size]`是有效的. (3认同)
  • 我想出了这个代码:`[nil,:equilateral,:isosceles,:scalene] [[a,b,c] .uniq.size]`但我觉得你的代码更具可读性. (2认同)

小智 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
Run Code Online (Sandbox Code Playgroud)


gle*_*ebm 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
Run Code Online (Sandbox Code Playgroud)

  • 你的意思是传递性:) (3认同)

Mik*_*nty 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
Run Code Online (Sandbox Code Playgroud)


小智 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
Run Code Online (Sandbox Code Playgroud)