2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Crystalで深い多重ループを楽に書くマクロ

Last updated at Posted at 2023-08-27

前回の記事の続きです。
https://qiita.com/theanine/items/9462b79b83c1aba412bd

前回の記事で多次元の配列を簡単に作るmacroを作りました。
多次元配列を作ると、各次元ごとにループをかけていくので、深いネストのループになりがちです。

前回取り上げたAtCoderの問題では10重ループとなりました。

(0..n1).each do |i1|
  (0..n2).each do |i2|
    (0..n3).each do |i3|
      (0..n4).each do |i4|
        (0..n5).each do |i5|
          (0..n6).each do |i6|
            (0..n7).each do |i7|
              (0..n8).each do |i8|
                (0..n9).each do |i9|
                  (0..n10).each do |i10|
                    何かの処理
                  end
                end
              end
            end
          end
        end
      end
    end
  end
end

どうせ、コピペで書いていくので、書くのはそこまで大変ではないですが、変更とかあるとしんどいですね。
そこで、前回に引き続きmacroで楽をしましょう。

macroのブロック

Crystalのmacroは高機能で、ブロックを受け取ることもできます。

args, bodyでブロックの引数や中身などにも分けて取得できて色々できそうですね。これを使って、多重ループマクロを作ってみます

多重ループマクロ

ということで以下のようなものを作ってみました。

macro rep(*a, &block)
  {% for i in 0...a.size %}
    ({{a[i]}}).each do |{{block.args[i]}}|
  {% end %} 
  {{ block.body }}
  {% for i in 0...a.size %}
    end
  {% end %}
end

使い方は以下のようにします。eachメソッドを持つオブジェクトを引数で渡せば良いです。範囲や配列、タプルなどを渡すことができます。

rep(1..2, {3,4,5}, 0..1) do |i, j, k|
  puts "#{i} #{j} #{k}"
end

これを実行すると以下のようにできます。

1 3 0
1 3 1
1 4 0
1 4 1
1 5 0
1 5 1
2 3 0
2 3 1
2 4 0
2 4 1
2 5 0
2 5 1

これで深いループもブロックのネストを深くせずにかけます。

冒頭で取り上げた10重ループは

rep(0..n1, 0..n2, 0..n3, 0..n4, 0..n5, 0..n6, 0..n7, 0..n8, 0..n9, 0..n10) do |i1, i2, i3, i4, i5, i6, i7, i8, i9, i10|
  何らかの処理
end

となります。

2
1
0

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?