LoginSignup
32
29

More than 5 years have passed since last update.

Array#product で多重ループを回避しよう

Last updated at Posted at 2015-02-27

複数の配列があり、その全ての組み合わせでループしたいときってありますよね。
そんな場合に以下のようなコードを書いて、なんとなく悲しみにくれたりしていませんか?

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

✌ ('ω' ✌ )三 ✌ ('ω') ✌ 三( ✌ 'ω') ✌ スッキリ!

32
29
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
29