2009-01-15練習:たのしいRuby
P.203 (1) square メソッドを定義する
数値からなる配列 nums に対して、その個々の要素を自乗した要素からなる 配列を返すメソッド square を 3 通りの方法で定義しましょう。
(a) collect を使う
def square1(nums) nums.collect{|i| i**2 } end nums = [1, 3, 5, 7, 9] p square1(nums)
実行結果
[1, 9, 25, 49, 81]
(b) collect は使わず、each を使う
def square2(nums) result = [] nums.each{|i| result << i**2 } return result end nums = [2, 4, 6, 8, 10] p square2(nums)
実行結果
[4, 16, 36, 64, 100]
(c) collect も each も使わず、インデックスと[ ]を使う
def square3(nums) nums.each_index{|index| nums[index] **= 2 } end nums = [1, 9, 25, 49, 81] p square3(nums)
実行結果
[1, 81, 625, 2401, 6561]
P.203 (2) sum_array メソッドを定義する
数値からなる配列 nums1 と nums2 に対して、それらの個々の要素を足し合わせた 要素からなる配列を返すメソッド sum_array を定義しましょう。
書いたもの
def sum_array(ary1, ary2) result = [] ary1.zip(ary2){|a, b| result << a + b } return result end nums1 = [1, 2, 3] nums2 = [4, 5, 6] p sum_array(nums1, nums2)
実行結果
[5, 7, 9]
rochefort さんの日記 を見て、zip と map を使えば、もっとすっきり書けることを知った。なるほどねぇ。
あと、ためしに、要素数が異なる配列を足してみた。案の定、ary1 のほうが少ないときは ary1 と同じ要素数の配列が返ってきたけど、ary1 のほうが多いときは、nil と Fixnum は足せないよ、というエラーが返ってきた。
このメソッドで足せるかどうかを事前にチェックすることも考えた。チェックするなら、配列の要素数が同じか、と、配列の要素が数値オブジェクトだけか、の 2 つかな。でも、チェックを入れると、その分、sum_array するのに時間がかかるし、いまいちかも。で、やっぱり、要素数が異なる配列を足そうとしたときなどのエラーは、実行時のエラーにお任せすることにした。
P.203 (3) balanced? メソッドを定義する
(, ), {, } という 4 つの文字を要素とした配列がある。この配列に対して、
カッコが正しく対応しているかを調べるメソッド balanced? を定義しましょう。
「カッコが正しく対応している」とは、以下のような状態のことです。
・( と ) の数が同じ
・{ と } の数が同じ
・「( )」の対応と「{ }」の対応が交差することはない
書いたもの 1
正規表現を使ってみた。
def balanced?(ary) str = ary.join while (/\(\)/ =~ str) || (/\{\}/ =~ str) result = str.gsub!(/\(\)|\{\}/, "") end if result == "" return true else return false end end p balanced?(%w! ( !) p balanced?(%w! { } !) p balanced?(%w! ( { { } ( ) } ( ) ) !) p balanced?(%w! ( { { ( } ( ) } ( ) ) !)
実行結果
false true true false
書いたもの 2
今度は、スタックを使って。
def balanced2?(ary) stack = [] ary.each {|elem| case elem when "(" stack << elem when "{" stack << elem when ")" if stack.last != "(" return false else stack.pop end when "}" if stack.last != "{" return false else stack.pop end else return false end } if stack.size == 0 return true else return false end end p balanced2?(%w! ( !) p balanced2?(%w! { } !) p balanced2?(%w! ( { { } ( ) } ( ) ) !) p balanced2?(%w! ( { { ( } ( ) } ( ) ) !)
実行結果
false true true false
引数 nums を書き換えることは意図したことではないです。手元のものは以下のように修正しました。
def square3(nums)
copy = nums.dup
copy.each_index{|index|
copy[index] **= 2
}
end
蛇足ですが、square3 は、最初はこんなふうに書いていました。
def square3(nums)
indexes = (0...nums.size).to_a
result = []
while index = indexes.shift
result << nums[index] ** 2
end
return result
end
これなら、nums を書き換えてはいなかったです。
インデックスの配列をわざわざつくらなくても、Ruby にはインデックスに対して何かをするメソッドがあるのではと思っていたところ、Array#each_index を見つけ、これを使いました。
マニュアルを読んで使い方を理解したつもりだったのですが、まだまだですね。