複数の配列があり、その全ての組み合わせでループしたいときってありますよね。
そんな場合に以下のようなコードを書いて、なんとなく悲しみにくれたりしていませんか?
index = 1
(2010..2015).each do |year|
(1..10).each do |number|
('a'..'z').each do |char|
puts("(#{index}) year: #{year}, num: #{number}, char: #{char}")
index += 1
end
end
end
そんなときに便利なのが Array#product です。
これは、レシーバの配列の要素と引数で与えられた配列の要素の全ての組み合わせ (デカルト積) を返してくれます。
しかも引数には複数の配列を指定できます。
※ Range オブジェクトのままでは product メソッドは利用できないので Array に変換しています。
Array(2010..2012).product(Array(1..2), Array('a'..'c'))
# [
# [2010, 1, "a"],
# [2010, 1, "b"],
# [2010, 1, "c"],
# [2010, 2, "a"],
# [2010, 2, "b"],
# [2010, 2, "c"],
# [2011, 1, "a"],
# [2011, 1, "b"],
# [2011, 1, "c"],
# [2011, 2, "a"],
# [2011, 2, "b"],
# [2011, 2, "c"],
# [2012, 1, "a"],
# [2012, 1, "b"],
# [2012, 1, "c"],
# [2012, 2, "a"],
# [2012, 2, "b"],
# [2012, 2, "c"]
# ]
この Array#product を利用して最初のコードを書き換えてみましょう。
(最初のコードとループの返り値が違いますが、そこはご容赦ください。)
Array(2010..2015).product(Array(1..10), Array('a'..'z')).each.with_index(1) do |(year, number, char), index|
puts("(#{index}) year: #{year}, num: #{number}, char: #{char}")
end
✌ ('ω' ✌ )三 ✌ ('ω') ✌ 三( ✌ 'ω') ✌ スッキリ!