黒魔術に手を染めてしまったかもしれない。
再帰の技法という本にある問題で、こんな感じの出力を表示する問題があった。*1
bo b1 b2 (b0 or (b1 and (not b2))) ---------------------------------------- false false false false false false true false false true false true false true true false true false false true true false true true true true false true true true true true
これをrubyで楽にできないかなーと思った。
「要素がb0,b1,b2の配列」を要素として持つ配列がつくれたら、あとは簡単。
要素の配列の要素数が2つのとき(b0,b1まで)
bool=[false,true] p bool.map{|a| bool.map{|b| [a,b]}}.inject{|a,b| a+b} #=>[[false, false], [false, true], [true, false], [true, true]]
要素の配列の要素数がnつのとき(b0,...b(n-1)まで)
いちいちたくさん書くのは面倒。
どうしたら簡単にできるんだろ?*2
式自体を文字列として作っちゃえばいいのかもしれない
def make_list(seed,n) symbols=("a".."z").to_a[1..n] x=symbols.inject(["",""]) do |result, element| result[0].concat("seed.map{ |#{element}| ") result[1].concat("} ") result end.join("[#{symbols.join(", ")}]") eval(x+%Q!#{eval("'.inject{|aa,bb| aa+bb}'*(n-1)")}!) end ## 表示用 ###### def prepare printf("%-6s %-6s %-6s %-10s\n",:bo,:b1,:b2,"(b0 or (b1 and (not b2)))") puts "-"*40 end prepare make_list([false,true],3).each do |b| printf("%-6s %-6s %-6s %-10s\n",b[0], b[1], b[2], b[0]||(b[1]&&(not b[2]))) end
eval使いまくり…
追記
こうすれば、evalを使わなくてもすんだ。
def f xs,ys xs.map{|x|ys.map{|y|[x,y]}}.inject{|aa,bb| aa+bb} end def make_list2(seed,n) Array.new(2,seed).inject{|re,e| f(re,e)}.each{|ee| ee.flatten!} end