Rubyで配列に対して重複を許す順列を列挙するメソッドを再帰で実装したが標準にもうありました
要するにこういうのの出力する要素数によらない版を作りたかった
(出力する要素数だけブロックを入れ子にしないといけないので)
def naive_enumerate array array.each do |a_1| array.each do |a_2| array.each do |a_3| yield [a_1, a_2, a_3] end end end end arr = [1, 3, 5] naive_enumerate arr do |a| p a end
出力結果はこんなかんじ
[1, 1, 1]
[1, 1, 3]
[1, 1, 5]
[1, 3, 1]
[1, 3, 3]
[1, 3, 5]
[1, 5, 1]
[1, 5, 3]
[1, 5, 5]
[3, 1, 1]
[3, 1, 3]
[3, 1, 5]
[3, 3, 1]
[3, 3, 3]
[3, 3, 5]
[3, 5, 1]
[3, 5, 3]
[3, 5, 5]
[5, 1, 1]
[5, 1, 3]
[5, 1, 5]
[5, 3, 1]
[5, 3, 3]
[5, 3, 5]
[5, 5, 1]
[5, 5, 3]
[5, 5, 5]
で、こういう実装をしてみたが
def enumerate_error array, n, buf=[] if n == 0 yield buf else array.each do |a| enumerate_error array, n-1, buf + [a] end end end arr = [1, 3, 5] enumerate_error arr, 3 do |a| p a end
`enumerate_error': no block given (LocalJumpError)というエラー発生
再帰的に呼び出してる所がブロック付きメソッド呼び出しになってないからですね
ブロックに渡された要素をまんま渡すよう実装
def enumerate array, n, buf=[] if n == 0 yield buf else array.each do |a| enumerate(array, n-1, buf + [a]) {|b| yield b} end end end arr = [1, 3, 5] enumerate arr, 3 do |a| p a end
で、無事完成したが、Ruby 1.9.2 からもう標準で実装されていたようです
arr = [1, 3, 5] arr.repeated_permutation(3) do |a| p a end
Array#permutation (Ruby 1.8.7から)
Array#combination (Ruby 1.8.7から)
Array#repeated_permutation (Ruby 1.9.2から)
Array#repeated_combination (Ruby 1.9.2から)
といたれり尽くせりのようです
http://ref.xaio.jp/ruby/classes/array