久しぶりにrubyで遊ぶ
rubyを始めた時に、くくを出力するプログラムを作ったりしました。
くくはこんな感じで書けると思います。
(9*9じゃないからnnかもしれません><)
def kuku n (1..n).map{ |x| (1..n).map{ |y| x * y}} end kuku(2) # => [[1, 2], [2, 4]]
これはn*nの要素で成り立ってます。
それなら、n*n*nの要素で成り立つくく的なものも定義できるはずです。
def kukuku n (1..n).map{ |x| (1..n).map{ |y| (1..n).map{ |z| x * y * z}}} end kukuku(2) # => [[[1, 2], [2, 4]], [[2, 4], [4, 8]]]
mapが3つになってしまいました><。
4,5,6...と増やしていった場合のくく的なものはどうなるんでしょう。
mapをたくさん書くのは面倒ですね。*1
一般的な形で定義したいところです。
というわけで少し考えてみました。出来上がったのが以下のようなものです。
def ku_n1 n, size, re=(1..n) (1..size-1).inject(re) do |r,_| r.map do |x| if x.respond_to? :map ku_n1(n,size-1,x ) else (1..n).map{ |y| x * y } end end end end
少し読みにくいかもとか思いました。
procで2つに分けると読みやすいかもしれません。
def ku_n2 n,size, re=(1..n) f = proc do |x| if x.respond_to?(:map) ku_n2(n,size-1,x) else (1..n).map{ |y| x * y} end end (1..size-1).inject(re){ |r,_| r.map{|x| f.call(x)}} end
速度の方はどうなのでしょうか?
前に実験したときの感覚からよると、ku_n2の方がとてもおそい気がします。
速度を計ってみましょう。
require 'benchmark' Benchmark.bmbm do |x| 1.upto(2){ |n| x.report("ku_n#{n}"){ send("ku_n#{n}", 10, 5)}} end
1.8の結果
(ruby 1.8.6 (2007-06-07 patchlevel 36) [i486-linux]) Rehearsal ----------------------------------------- ku_n1 1.530000 0.170000 1.700000 ( 1.695043) ku_n2 4.820000 0.290000 5.110000 ( 5.115461) -------------------------------- total: 6.810000sec user system total real ku_n1 1.580000 0.140000 1.720000 ( 1.736124) ku_n2 4.860000 0.260000 5.120000 ( 5.127700)
記憶が確かなら、block内で関数を読んでいる時に重くなるような感じです。
(1.9だとどうなっているかは分かりません><)
1.9でも計ってみました
(ruby 1.9.0 (2008-03-01 revision 15664) [i686-linux]) Rehearsal ----------------------------------------- ku_n1 0.560000 0.000000 0.560000 ( 0.563815) ku_n2 1.010000 0.000000 1.010000 ( 1.007135) -------------------------------- total: 1.570000sec user system total real ku_n1 0.550000 0.000000 0.550000 ( 0.545552) ku_n2 0.950000 0.000000 0.950000 ( 0.954810)
1.8の時は3倍くらい差があったのですが、1.9では2倍くらいになっています。
というか、1.9は速いですね。とても速いです。
*1:evalを使って作るというのも何だか邪道な感じです><