Array#product を使って配列の操作を楽にする

配列が次のように与えられているときに,

a = %w(a b c d e f g h i j)
b = %w(1 2 3 4 5 6 7 8 9 0)

各要素の総当りでこのような配列を作りたい場合,

["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "e0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9", "g0", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9", "h0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8", "i9", "i0", "j1", "j2", "j3", "j4", "j5", "j6", "j7", "j8", "j9", "j0"]

こんなふうに書いてました.

# Array#map
def cross(a, b)
  a.map{|elem_a| b.map{|elem_b| elem_a.to_s + elem_b.to_s}}.flatten
end

mapのなかでmapは気持ち悪いなーと思い調べていたところ,
Array#productのお手軽さを再発見.

# Array#product
def cross(a,b)
  a.product(b).map{|elem| elem.join()}
end

Array#productを使うと,以下のような総当りの組み合わせの配列が
ネストされて返されるので,個々の配列について処理をしてあげればいいわけです.

[["a", "1"], ["a", "2"], ["a", "3"], ["a", "4"], ["a", "5"], ["a", "6"], ["a", "7"], ["a", "8"], ["a", "9"], ["a", "0"], ["b", "1"], ["b", "2"], ["b", "3"], ["b", "4"], ["b", "5"], ["b", "6"], ["b", "7"], ["b", "8"], ["b", "9"], ["b", "0"], ["c", "1"], ["c", "2"], ["c", "3"], ["c", "4"], ["c", "5"], ["c", "6"], ["c", "7"], ["c", "8"], ["c", "9"], ["c", "0"], ["d", "1"], ["d", "2"], ["d", "3"], ["d", "4"], ["d", "5"], ["d", "6"], ["d", "7"], ["d", "8"], ["d", "9"], ["d", "0"], ["e", "1"], ["e", "2"], ["e", "3"], ["e", "4"], ["e", "5"], ["e", "6"], ["e", "7"], ["e", "8"], ["e", "9"], ["e", "0"], ["f", "1"], ["f", "2"], ["f", "3"], ["f", "4"], ["f", "5"], ["f", "6"], ["f", "7"], ["f", "8"], ["f", "9"], ["f", "0"], ["g", "1"], ["g", "2"], ["g", "3"], ["g", "4"], ["g", "5"], ["g", "6"], ["g", "7"], ["g", "8"], ["g", "9"], ["g", "0"], ["h", "1"], ["h", "2"], ["h", "3"], ["h", "4"], ["h", "5"], ["h", "6"], ["h", "7"], ["h", "8"], ["h", "9"], ["h", "0"], ["i", "1"], ["i", "2"], ["i", "3"], ["i", "4"], ["i", "5"], ["i", "6"], ["i", "7"], ["i", "8"], ["i", "9"], ["i", "0"], ["j", "1"], ["j", "2"], ["j", "3"], ["j", "4"], ["j", "5"], ["j", "6"], ["j", "7"], ["j", "8"], ["j", "9"], ["j", "0"]]

で,2つ以上の配列を組み合わせたいときには

def cross(a,*b)
  p a.product(*b)
  a.product(*b).map{|elem| elem.join()}
end

と,第2引数で複数の配列を受け取ってそのままArray#productに渡しちゃえばいいんですね.