ExcelのVBAは最速ではありませんが、行の大きなサンプルをループする最も効率的な(つまり、最も速い)方法が必要です。
現在私が持っているもの:
For Each c In Range("$A$2:$A$" & Cells(Rows.count, "A").End(xlUp).row
' do stuff
Next c
'do stuff'には、あちこちに行を挿入することが含まれます(そのため、範囲の動的ルックアップを維持する必要があります)。
アイデア(10,000行以上)
編集私はすでに使用しています
Application.ScreenUpdating = False
Application.Calculation = xlManual
列Aの1万行をループするだけの場合は、その行をバリアント配列にダンプしてからループします。
次に、必要に応じて行を追加しながら新しい配列に要素を追加し、Transpose()を使用して配列を1回の移動で範囲に配置するか、反復子変数を使用してどの行にいるかを追跡し、追加できますそのように行。
Dim i As Long
Dim varray As Variant
varray = Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row).Value
For i = 1 To UBound(varray, 1)
' do stuff to varray(i, 1)
Next
各セルを評価した後に行を追加する方法の例を次に示します。この例では、列Aに単語「foo」を持つすべての行の後に行を挿入します。A2から開始しているため、挿入中に変数iに「+2」が追加されるわけではありません。 A1で配列を開始した場合、+ 1になります。
Sub test()
Dim varray As Variant
Dim i As Long
varray = Range("A2:A10").Value
'must step back or it'll be infinite loop
For i = UBound(varray, 1) To LBound(varray, 1) Step -1
'do your logic and evaluation here
If varray(i, 1) = "foo" Then
'not how to offset the i variable
Range("A" & i + 2).EntireRow.Insert
End If
Next
End Sub
[〜#〜] edit [〜#〜]要約と推奨事項
を使って for each cell in range
構文自体は自体ではありません。 is遅いのは、ループ内でExcelに繰り返しアクセスすることです(セル値の読み取りまたは書き込み、フォーマットなど、行の挿入/削除など)。
遅すぎるものは、ニーズによって大きく異なります。まれにしか使用されない場合、実行に数分かかるSubは問題ないかもしれませんが、10秒かかるサブは頻繁に実行されると遅すぎるかもしれません。
したがって、いくつかの一般的なアドバイス:
for index = max to min step -1
)value
以外のセルプロパティにアクセスする必要がある場合、セル参照にこだわる例(テストされていません!)
Dim rngToDelete as range
for each rw in rng.rows
if need to delete rw then
if rngToDelete is nothing then
set rngToDelete = rw
else
set rngToDelete = Union(rngToDelete, rw)
end if
endif
next
rngToDelete.EntireRow.Delete
元の投稿
セルをループすることはbadであり、バリアント配列をループすることはgood。私もこれを長年擁護してきました。あなたの質問に考えさせられたので、私は驚くべき(とにかく)結果でいくつかの短いテストを行いました:
テストデータセット:セル内の単純なリストA1
.. A1000000
(1,000,000行)
テストケース1:配列をループする
Dim v As Variant
Dim n As Long
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
v = r
For n = LBound(v, 1) To UBound(v, 1)
'i = i + 1
'i = r.Cells(n, 1).Value 'i + 1
Next
Debug.Print "Array Time = " & (GetTickCount - T1) / 1000#
Debug.Print "Array Count = " & Format(n, "#,###")
結果:
Array Time = 0.249 sec
Array Count = 1,000,001
テストケース2:範囲をループする
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
For Each c In r
Next c
Debug.Print "Range Time = " & (GetTickCount - T1) / 1000#
Debug.Print "Range Count = " & Format(r.Cells.Count, "#,###")
結果:
Range Time = 0.296 sec
Range Count = 1,000,000
したがって、配列のループはより高速ですが、19%だけ-予想よりはるかに少ないです。
テスト3:セル参照で配列をループする
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
v = r
For n = LBound(v, 1) To UBound(v, 1)
i = r.Cells(n, 1).Value
Next
Debug.Print "Array Time = " & (GetTickCount - T1) / 1000# & " sec"
Debug.Print "Array Count = " & Format(i, "#,###")
結果:
Array Time = 5.897 sec
Array Count = 1,000,000
テストケース4:セル参照を含むループ範囲
T1 = GetTickCount
Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells
For Each c In r
i = c.Value
Next c
Debug.Print "Range Time = " & (GetTickCount - T1) / 1000# & " sec"
Debug.Print "Range Count = " & Format(r.Cells.Count, "#,###")
結果:
Range Time = 2.356 sec
Range Count = 1,000,000
したがって、単一の単純なセル参照を使用したイベントでは、ループは1桁遅くなり、さらに、範囲ループは2倍高速になります。
したがって、結論は最も重要なのはループ内での処理であり、速度が本当に重要な場合はすべてのオプションをテストします
FWIW、Excel 2010 32ビット、Win7 64ビットでテスト済み
ScreenUpdating
off、Calulation
マニュアル、Events
は無効です。For Eachは、何らかの理由でI = 1からXよりもはるかに高速です。同じ辞書を調べてみてください。
dDictのDkeyごとに1回、
dkey = lbound(dDict.keys)からubound(dDict.keys)まで
=>同じコンストラクトを使用している場合でも、大きな違いに気付くでしょう。