処理高速化に大きな効果があるのが、セル選択を減らす事です
しかし、それを実現するために1行のコードが長くなる場合があります
処理速度の向上に繋がりますが、恐ろしく可読性が低下する可能性があります
処理速度よりも可読性の方が圧倒的に重要です
でも、処理速度だって重要です
そんな時に使う方法として、1行を短くしつつセルは選択しないようにする方法です
考え方は簡単で、変数に順番に代入させていき
最終的に確定したセル範囲を選択するようにします
こうすると、可読性を保ちつつセル選択の回数を減らすことが出来ます
使用例
Dim 取得用Range As Range Set 取得用Range = Range("A1").CurrentRegion Set 取得用Range = 取得用Range.Cells(取得用Range.Cells.Count) Set 取得用Range = Range(Range("A2"), 取得用Range) Set 取得用Range = Intersect(Range("B1").EntireColumn, 取得用Range) 取得用Range.Select
実際に動きを確認しましょう、今回作成したコードが以上のものです
処理の動きとしては、表の指定列の見出しを含まないデータ範囲です
画像の選択された範囲を取得するのが、目標です
よくあるパターンの取得例やと思います
Dim 取得用Range As Range
まずは、最初に変数に代入させてセル選択を行うため、それを可能にするためにRange型変数の宣言を行います
これ以降は、Rangeオブジェクトでの指定を行わずにこの変数名で行います
Set 取得用Range = Range("A1").CurrentRegion
最初に表全体の範囲を取得します
ここから順番に部分範囲を取得していきながら、必要な部分のみに除外していきます
表全体の取得にはCurrentRegionプロパティを使用して取得します
セルA1を含む空白セルに囲まれた、表範囲が取得されます
この時点から、変数にセルを代入しています
Set 取得用Range = 取得用Range.Cells(取得用Range.Cells.Count)
次に、取得したセル範囲の中での最後のセルを取得します
これは最終行を取得したいためです
基本的に表という仕様では、見出しからデータの開始までの範囲が変化することはほぼありません
画像でいうところの、1行目が見出しで2行目以降がデータ範囲である
という、大前提の話です
つまり、最終行が取得できれば2行目から指定することでデータ範囲行を特定することができる訳です
この最終行の取得には色々な方法がありますので、これが最善とは言いませんが
表範囲という前提で考えると、Endプロパティでも良いのですが取得したい列が常にデータで埋められている前提である必要があります
しかし、この記事コードで取得すればデータ範囲に空白があってもちゃんと表範囲として取得することが出来ますので、汎用的なコードかなと思います
Set 取得用Range = Range(Range("A2"), 取得用Range)
ここで、始点セルまでを範囲取得しています
この時点で表範囲の見出しを除いたデータ範囲が取得された状態になります
これには2つ方法があり、Resizeプロパティを使用する方法と最後のセルから始点セルまでを範囲取得する方法です
今回は、後者の方法を採用します
動きがこっちのほうがイメージしやすいような気がしたので
もし、Resizeプロパティを使用する場合は、表範囲を取得してからすぐにこのプロパティで見出し行を除外してあげればいいだけですね
これに関しては、ここでは割愛します
Set 取得用Range = Intersect(Range("B1").EntireColumn, 取得用Range)
ここで最後に表範囲内の指定の列を取得します
Intersectメソッドを使用して、指定列との重複範囲を取得しています
引数では、2つありますが1つ目の引数では、指定列を指定しています
Range("B1").EntireColumn
EntireColumnプロパティは、指定したセルを含む列全体を取得するプロパティです、なのでここではB1セルを含む列、つまりB列が取得される形になります
このB列とここまでで取得した配列変数(表範囲のデータ範囲のみ)の重複する範囲、となるのでデータ範囲のB列が取得されます
取得用Range.Select
ここまでで取得が完了したので、変数セルを選択状態にして完了です
選択せずに、この変数セルに値を入力することもできます
また、この範囲をFor Eachループで1セルずつ処理を行うこともできます
Rangeオブジェクトなので、さまざまな用途に使用できますので、いろいろな応用方法を考えてみてください
Intersect(Range("B1").EntireColumn, Range(Range("A2"), Range("A1").CurrentRegion.Cells(Range("A1").CurrentRegion.Cells.Count))).Select
ちなみに、これらを1行で納めると上記のような形になります
恐ろしく長いコードになり、とても可読性の良いコードとは言えません
1行に出来るコードをわざわざ分割するのは、遠回りをしているような気がするかもしれませんが、コードの可読性を上げるためには重要な考え方です
可読性を維持しつつ、処理速度も向上させる考え方です
最後に、このコードの動きを順番にセル選択をした場合と、記事のように変数で選択した場合との処理時間の差です
処理秒数 | 記事方法 | 都度選択 |
1回目 | 1.01953125 | 12.55078125 |
2回目 | 1.0078125 | 12.23046875 |
3回目 | 1.01171875 | 13.19921875 |
4回目 | 1.015625 | 13.2109375 |
5回目 | 1.0234375 | 12.33203125 |
6回目 | 1.02734375 | 12.234375 |
7回目 | 1.01171875 | 12.11328125 |
8回目 | 1.015625 | 12.421875 |
9回目 | 1.03515625 | 12.125 |
10回目 | 1.03515625 | 12.12109375 |
出来レースのように、完全に結果に差が出ることは分かり切った比較なので、特にコードは記載しません
概要としては、セル選択を1000回実行した場合の処理時間を10回計測したものです
いまさらですが、セル選択を少なくするだけでこれだけの処理速度向上につながるということですね
ごくごく当たり前のことですが、変数に代入させるものは変数も使用できる
そんな方法を利用する考え方をしてもらいたい、という話でした