直積

class Array
  def cartesian_product
    top = shift
    if empty?
      top
    else
      c = cartesian_product
      top.inject [] do |r, i|
        c.each do |j|
          r.push [i, *j]
        end
        r
      end
    end
  end
end

dice = [1,2,3,4,5,6]
puts [dice, dice].cartesian_product.map {|i| "(#{i.join ','})"}.join ','
#=>(1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(2,1),(2,2),(2,3),(2,4),(2,5),(2,6),(3,1),(3,2),(3,3),(3,4),(3,5),(3,6),(4,1),(4,2),(4,3),(4,4),(4,5),(4,6),(5,1),(5,2),(5,3),(5,4),(5,5),(5,6),(6,1),(6,2),(6,3),(6,4),(6,5),(6,6)

Ruby1.8.7からArray#productでできるらしいことをこれを書いてから知りました。でもArray#productとはちょっとインターフェイスが異なるようです。こちらはレシーバーが2次元配列であることを仮定してその各要素である配列たちから直積を作りますがArray#productでは「組み合わせる集合」を引数として渡します。

defの中に丸括弧が登場しない、配列を扱うメソッドなのに配列の添字で要素にアクセスする書き方を使わずに書けた、あとself省略のメソッド呼び出し多用、再帰など結構自分としては面白く書けたかな、と思ったので記念に載せておきます。

2次元配列を仮定、と書きましたが実際は配列の中の要素がeachを使えれば何でもいいので…

dice = (1..6)
puts [dice, dice].cartesian_product.map {|i| "(#{i.join ','})"}.join ','

でも同じ結果になります。柔軟ですね。