- 2007/10/05
- Ruby
Satoshi NakajimaさんのLife is beautifulでRubyお題が出ていたのでやってみた。かなり出遅れているけど。
ということで、ここで問題。以下の二つのプログラムをfor/whileを使わずにイテレータで書き直してみていただきたい。私はどちらの例も、イテレータで書いた方がずっと美しいと思うのだが、いかがだろう。
そもそもイテレータって何?っていう状態だったので、もうシックハック。とりあえず正解かどうかは分からないけど、自分なりに書いてみた。回答は続きで。
例題1
def hello(to, *mesg) print "Hello, ", to, ".\n" print "-- message -- \n" for m in mesg print m, "\n" end end name = "ZARU" message = ["こんにちわ","さようなら"] hello(name,message)
*mesg で引数を配列として受け取って、for で回して表示するというもの。これを for を使わずイテレータでやる。
そもそも、イテレータとは受け取ったブロックを実行するメソッド
…と解説されていたけど、よーわからん。ブロックというのは、色々な式をまとめたものらしい。つまり、メッソドはオブジェクトだけじゃなくて、式(動作?)自体を処理できるということ?(あってる?)
というわけで、こんなソースを最初に書いてみた。
def helloIterator(to)
print "Hello, ", to, ".\n"
print "-- message -- \n"
yield
end
name = "ZARU"
message = ["こんにちわ","さようなら"]
helloIterator(name) {message.each do |m| print m,"\n" end}
ん?なんか逆にすっきりしていないような…。覚えたての yield を使ってはみたが。
じゃあ、ブロック自体を中に入れてみるか、というわけで、次に書いたのはこんな感じ。
def helloIterator(to,*mesg) print "Hello, ", to, ".\n" print "-- message -- \n" mesg.each do |m| print m, "\n" end end name = "ZARU" message = ["こんにちわ","さようなら"] helloIterator(name,message)
例題2
def fact(n) return 1 if n==0 f=1 while n>0 f*=n n -= 1 end return f end print fact(10)
1 * 10 * 9 * 8 * ... っていう n をデクリメントして乗算する処理。つまり階乗。これを整数のイテレータを使って書き換えてみる。
整数のイテレータには、times, upto, downto というものがある。今回は downto を使うと上手くいきそうだ。downto とは
n.downto(m) ブロック
n を1ずつ減らしながらブロックを実行し、m と等しくなったら処理を終了する。これを while で置き換えたソース。
def factIterator(n) return 1 if n==0 f=1 n.downto(1) do |i| f*=i end return f end print factIterator(10)
よし。とりえあず処理結果は同じになった。あとはイテレータを理解しているかどうか…。うーん。