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