またまた何か変な小ネタですが…ちょっととあることをやっていると「Excelにおいて、指定した領域のうち、ある部分だけが含まれない状態を作りたい」という不思議な要求が出てきたので、それをかなえるべくVBAで処理を組んでみました。Excel限定ですので多分VBA以外でこんな処理は作れないでしょうし、作る意味もない、というか。
コードは…
こんな感じでしょうか。
Function ExcludeRange(rr As Range, re As Range) As Range Dim ra As Range, rt As Range, ri As Range, ret As Range For ai = 1 To rr.Areas.Count Step 1 Set ra = rr.Areas(ai) For i = 1 To ra.Rows.Count Step 1 For j = 1 To ra.Columns.Count Step 1 Set rt = Range(Cells(ra.Row + i - 1, ra.Column + j - 1), Cells(ra.Row + i - 1, ra.Column + j - 1)) Set ri = Application.Intersect(rt, re) If ri Is Nothing Then If ret Is Nothing Then Set ret = rt Else Set ret = Application.Union(ret, rt) End If End If Next j Next i Next ai Set ExcludeRange = ret End Function
構想は…
考え方はこの通り。
- Rangeから直接差のRangeを取り出すことはできないので、「重なっていない」セルだけをくっつけていくしかない
- 仕方がないので、Forループで一つ一つ領域→行→列を巡回して指されたRangeに重ならないかどうかを調べる(Intersectでのチェック)
- あとは結果となる領域にくっつけていく
になります。なお、はじめのRangeに含まれているすべてのセルを巡回する特性上、かなり遅いです。参考として出しているだけですので、本気に使いたいのであればもう少し最適化が必要だと思います。(行方向のみに限定したり、列方向に限定する、など)ちゃんとRangeオブジェクトのためにIntersectやらUnionやらOffsetやらの処理はあるのに…。
まあ、ゲームの描画でも、DirtyRect管理で重なっている文の検出やら最小の再描画領域になるようにRectを再構築するなどはありそうですが、指定した範囲の除外なんていうのはほぼ出てこないパターンでしょう。アルゴリズムを考えてみる分には面白いのかもしれませんが。