Rubyを触ってみる 3限目
九九を並べるのはできたんで、今度は罫線を足して表らしく。 罫線を書くサンプルはこんな感じ。
for i in 1..9
for j in 1..9
print "+---"
end
puts "+"
for j in 1..9
print "|" + " #{i * j}"[-3..-1]
end
puts "|"
end
for j in 1..9
print "+---"
end
puts "+"
なんか、わざと悪い例らしい。 結果は問題ないけどね。
$ ruby test_3.rb
+---+---+---+---+---+---+---+---+---+
| 1| 2| 3| 4| 5| 6| 7| 8| 9|
+---+---+---+---+---+---+---+---+---+
| 2| 4| 6| 8| 10| 12| 14| 16| 18|
+---+---+---+---+---+---+---+---+---+
| 3| 6| 9| 12| 15| 18| 21| 24| 27|
+---+---+---+---+---+---+---+---+---+
| 4| 8| 12| 16| 20| 24| 28| 32| 36|
+---+---+---+---+---+---+---+---+---+
| 5| 10| 15| 20| 25| 30| 35| 40| 45|
+---+---+---+---+---+---+---+---+---+
| 6| 12| 18| 24| 30| 36| 42| 48| 54|
+---+---+---+---+---+---+---+---+---+
| 7| 14| 21| 28| 35| 42| 49| 56| 63|
+---+---+---+---+---+---+---+---+---+
| 8| 16| 24| 32| 40| 48| 56| 64| 72|
+---+---+---+---+---+---+---+---+---+
| 9| 18| 27| 36| 45| 54| 63| 72| 81|
+---+---+---+---+---+---+---+---+---+
次のスライドには次のように書いてある。
- 最初のロジックが埋もれて見えない
- 表のための記述が多くて構造がみえない
- Rubyならもっとシンプルにしろ
PHP でもシンプルにできるわと思いつつ、Ruby ならもっとスマートに出来ると期待して読み進める。
(1..9).each {|i|
puts "+---" * 9 + "+"
(1..9).each {|j| print "|" + " #{i * j}"[-3..-1]}; puts"|"
}
puts "+---" * 9 + "+"
なんだかえらい短くなったなあ。
イテレータでシンプルに ... って、そんな高尚なお言葉つかいませんの。ポインタで進める配列のループ、くらいのテキトーな解釈が私には関の山ね。
さりげなく「実は for 文は each の別記法なのだ」とか書いてある。php だと each はポインタ位置の配列を取り出すだけだから、foeach が該当で間違いなさげ。
{} は do end で書く方法もあるみたい。 for i in 1..9 { hogehoge } でいくか for i in 1..9 do hogehoge end でいくか。(1..9).each{|i| hogehoge } でいくか (1..9).each do |i| hogehoge end でいくか。 好みの問題ってことでいいのかしら ? 悩むなあ ( 優柔不断 ) 。
次、行の単位を意識して、とある。
(1..9).each {|i|
puts "+---" * 9 + "+"
puts (1..9).reduce('') {|s, j| s += ("|" + " #{i * j}"[-3..-1])} + "|"
}
puts "+---" * 9 + "+"
これでソースの1行に1行分の処理を合わせて。
「reduceなんか使ってRubyらしい?」って書いてあるけど、Ruby では injcect で Python が reduce ってサイトがあった。まあ、どっちにしてもよくわかんないけど PHP の array_reduce みたいな感じかな。再帰関数なのは間違いなさそう。
調べてみたらエイリアスみたいなんで reduce を incejt にしたら普通に動くあたりまえ体操。CODA2には reduce がまだ入ってないみたいでサジェストされなかったけどね。
そこのサンプルをみてたら、もしかしてスライドの例の += は + だけでいいんじゃね ? という気がしてやってみたらこれもまた普通に動くあたりまえだのクラッカー。enum.inject(init) {|memo, item| block } の memo に block の返り値が入るんだろうと思って。
init は省略できるのかと思ったら String can't be coerced into Fixnum (TypeError) とか出てきたよ。ただの初期値かと思ったら文字型だと宣言する意味でやんなきゃだめなのか、これ。まあ、なんとなく納得。
ふーん、inject / reduce は面白そう。 array_reduce の時は恥ずかしながらよくわかなんかったけどね。
おまけまで行ってみよう。
require 'pp'
pp (1..9).map{|i| (1..9).map{|j| i * j}}
pp ってなんぞ ? map もなんぞ ?
$ ruby test_6.rb
[[1, 2, 3, 4, 5, 6, 7, 8, 9],
[2, 4, 6, 8, 10, 12, 14, 16, 18],
[3, 6, 9, 12, 15, 18, 21, 24, 27],
[4, 8, 12, 16, 20, 24, 28, 32, 36],
[5, 10, 15, 20, 25, 30, 35, 40, 45],
[6, 12, 18, 24, 30, 36, 42, 48, 54],
[7, 14, 21, 28, 35, 42, 49, 56, 63],
[8, 16, 24, 32, 40, 48, 56, 64, 72],
[9, 18, 27, 36, 45, 54, 63, 72, 81]]
どうやら二次元配列が出来るみたい。
pp って PHP の print_r みたいなもん ?
これを書式化すれば良いのかもめ。
まあ、続きは今度。