2011-01-20 9 views
14

私はRuby Koansを使ってabout_triangle_project.rbを作成しました。このメソッドでは、メソッド、三角形のコードを記述する必要があります。これらの項目のRuby Koansのより洗練されたソリューション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 

:triangle.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

を、私は次のメソッドを作成しました「プログラムを学ぶ」には、常に複数の方法があります。上記のコードは動作しますが、私はこれを行うよりエレガントな方法があると考えています。そのような方法をより効率的かつコンパクトにする方法についての考えを提供してくれる人はいますか?

もう一つ興味深いのは、正三角形を決定するために、(a == b == c)の条件を作成できなかったことです。それは正三角形の証明ですが、Rubyはその構文を嫌います。なぜこれが簡単な説明がありますか?

+1

'=='は値を受け入れる演算子です( '*'や '/'など)。 'true'または' false'を返します。 1 == 1 == 1は '(1 == 1)== 1と等価であるため、' false 'と評価されます)。 – glebm

+1

':= b == c"の構文をサポートしています。(またはa == b)&&(b == c) – pkananen

+0

Pythonは "a == b == c"構文をサポートしています「a

答えて

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 
+0

ありがとう、さようなら! (そして上記の答えも) – erinbrown

+3

あなたは推移性を意味します:) – Anurag

55

すなわち理由のために簡単に説明があります:Rubyで

==は、特定の機能を実行する演算子です。演算子には、適用順序を決定するためのルールがあります。たとえば、a + 2 == 3は、等価チェックの前に加算を評価します。しかし、一度に1人の演算子しか評価されません。等価チェックでtrueまたはfalseと評価されるため、2つの等価チェックが隣り合っているのは意味がありません。いくつかの言語ではこれが許されていますが、まだ正しく機能していません。なぜなら、の場合はtrue == cと評価されていて、数学的にはa == b == cであっても当てはまりません。

よりエレガントな解決策について:私はチャックのクールuniq.size技術を借りて、オブジェクト指向のソリューションにそれを働いた

[:equilateral, :isosceles, :scalene].fetch([a,b,c].uniq.size - 1) 
+0

ありがとう、チャック!私は大文字小文字を使ってuniqやフェッチを使っていますが、それは非常にクールです(なぜ私はRubyが好きですか?)。 – erinbrown

+3

+1の 'uniq.size';それはエレガントです。興味深いことに、 '[...] [[...]。uniq.size]'が有効なので、 'fetch'を使うことを選択しました。 – Phrogz

+0

@Phrogz:最初はそう書いていましたが、人々がいつも楽しんでいるようなPerlコードのように、読めないほど読めなかったので、読んでみたいものに少なくとも近似したと思いました。 – Chuck

5

case [a,b,c].uniq.size 
when 1 then :equilateral 
when 2 then :isosceles 
else  :scalene 
end 

あるいは、でも簡潔(あまり読み) 。もともと私は単なる責任の原則を維持するために、引数の検証をガード句として抽出したかったのですが、両方のメソッドが同じデータで動作していたので、それらはオブジェクトにまとめられていると思いました。

# 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 
+0

これは、about_triangle_project_2.rbのテスト部分にも最適です。私はあなたのソリューションをコピー/パスタしました。私のマシンコード版よりはるかにエレガントでした。 – TALLBOY

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 
+0

+1不要な比較を避けるために注文を巧みに使用する。 –

+0

これを動作させるには、 クラスTriangleError SteveO7

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 
+0

私は実装したものよりも洗練されたソリューションを探しましたが、この記事は1年半後に発見されました...しかし、私はこのソリューションが本当に好きだと言わなければなりません。それは非常に読みやすいきれいなアプローチです。名声! – bigtunacan

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 
+0

私はこれが完全により正確なエラーフィードバックを与えるために並べ替えを利用していて、読んで最短で読みやすいのが好きです。しかし、帰りは必要ありません。 – dansalmo

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 
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 
2

matlabの世界から来て、私は関数 'any'と 'all'の配列に慣れていて、ルビー。従って:

def triangle(a, b, c) 
    eqs = [a==b, a==c, b==c] 
    eqs.all?? :equilateral : eqs.any?? :isosceles : :scalene 
end 

可読性の面では、計算時間...(ruby noob)が最適かどうかは分かりません。

関連する問題