アルゴリズム: Dictionaryオブジェクト高速化手法

EXCEL

アルゴリズム: Dictionaryオブジェクト高速化手法

導入(問題設定)

VBAで大量のデータを扱う際、誰もが一度は「遅い!」と嘆いた経験があるでしょう。特にExcelシート上でのRange.Findメソッドや、二重・三重ループによる検索・比較処理は、データ件数が数千、数万に膨れ上がると実用に耐えないレベルのパフォーマンスに陥りがちです。

例えば、以下のようなシナリオです。 – 10万行のデータから特定のキーを持つ行を高速に探し出す。 – 2つの巨大なリスト(数万件ずつ)を突き合わせて共通の項目を抽出する。 – 数十万行のログデータから重複する行を排除し、ユニークな情報のみを集計する。

このような課題に対し、VBAの標準機能だけでは限界があります。そこで本稿では、Scripting.Dictionaryオブジェクト(以下、単にDictionary)を駆使した高速化テクニックに焦点を当て、その内部動作から実用的な堅牢化、さらには隠れた落とし穴まで、プロフェッショナルな視点から深く掘り下げて解説します。

理論の要点

Dictionaryオブジェクトの高速性の秘密は、その内部実装が「ハッシュテーブル」である点にあります。

ハッシュテーブルの基本

ハッシュテーブルは、キーと値をペアで格納するデータ構造で、キーから直接値を高速に検索できるのが特徴です。その鍵を握るのが「ハッシュ関数」です。

  1. ハッシュ値の計算: Dictionaryにキーを追加する際、内部でキーの「ハッシュ値」が計算されます。これはキーを固定長の数値に変換する処理です。
  2. インデックス化: このハッシュ値が、内部の配列(バケット)のインデックスとして利用されます。これにより、キーがどの位置に格納されているかを瞬時に特定できます。
  3. 平均O(1)の性能: 理想的なハッシュ関数とバケット配置であれば、キーの追加、検索、削除といった操作は、データの量に関わらずほぼ一定の時間で完了します(オーダー表記でO(1))。これがDictionaryの圧倒的な速度の源です。

ハッシュ衝突(コリジョン)と解決

異なるキーが同じハッシュ値を生成してしまうことを「ハッシュ衝突」と呼びます。これを解決するために、ハッシュテーブルは様々な戦略を取ります。一般的なのは「チェイン法」(衝突したキー・値ペアをリンクリストなどで連結する)や「オープンアドレス法」(空いている別のバケットを探す)です。

衝突が増えると、O(1)性能は損なわれ、最悪の場合O(N)(線形検索と同じ)に劣化することもあります。しかしScripting.Dictionaryは、一般的に適度な衝突解決メカニズムが実装されており、実用上はO(1)に近い性能を発揮します。

CompareModeの重要性

DictionaryCompareModeプロパティは、キーの比較方法を決定します。これが性能に大きく影響を与えます。

  • vbBinaryCompare (既定値): バイナリ比較。大文字と小文字を区別します(例: “ABC” と “abc” は異なるキー)。内部的には、キーのバイト列を直接比較するため非常に高速です。
  • vbTextCompare: テキスト比較。大文字と小文字を区別しません(例: “ABC” と “abc” は同じキー)。このモードでは、比較時に内部で文字列の正規化や変換処理が走るため、vbBinaryCompareよりもパフォーマンスが低下します。

常にvbBinaryCompareの使用を強く推奨します。大文字小文字を区別しない検索が必要な場合は、キーを事前に全て大文字 (UCase) または小文字 (LCase) に変換してからDictionaryに格納するなどの前処理を行うべきです。

VBA Collectionとの比較

VBAにはもう一つ、キーと値を扱うCollectionオブジェクトがありますが、これは通常Dictionaryよりも低速です。Collectionは内部的にはリンクリストや配列を用いた線形検索に近く、キー検索にO(N)の時間が必要となるため、大量データには不向きです。Dictionaryはハッシュテーブルの恩恵により、オーダーが桁違いに高速です。

graph TD
    A["データ追加/検索要求"] --> B{"キーからハッシュ値を計算"};
    B --> C{"ハッシュ値に基づきバケットを特定"};
    C --> D{"バケット内の要素を検索"};
    D -- 衝突発生 --> E["衝突解決アルゴリズム"];
    E -- 解決 --> D;
    D -- キー一致 --> F["目的のデータにアクセス"];
    D -- キー不一致 --> G["データなし/追加"];

    subgraph 比較モードによる性能差
        H["キー比較処理"] --> |vbBinaryCompare| I["高速なバイト列比較"];
        H --> |vbTextCompare| J["低速な言語依存比較/正規化"];
    end

実装(最小→堅牢化)

VBAにおけるDictionaryの使用法と、実運用に耐える堅牢なコードの書き方を解説します。

参照設定について

Scripting.Dictionaryを使用するには、通常VBEの「ツール」→「参照設定」で「Microsoft Scripting Runtime」にチェックを入れる必要があります。これにより、IDEのオートコンプリートが効き、開発効率が向上します。 参照設定を避けたい場合は、CreateObject("Scripting.Dictionary")を使用することも可能ですが、その場合はコンパイル時バインディングの恩恵(実行速度の向上やタイプミスの早期発見)を受けられません。本稿では参照設定を前提とします。

最小実装例

基本的なDictionaryの操作を見ていきましょう。

' 参照設定: Microsoft Scripting Runtime

Sub BasicDictionaryOperations()
    Dim dict As Scripting.Dictionary
    Set dict = New Scripting.Dictionary

    ' --- CompareModeの設定(重要) ---
    ' Binary比較(既定値だが明示的に設定推奨)
    dict.CompareMode = vbBinaryCompare
    ' Text比較(非推奨だが、必要なら)
    ' dict.CompareMode = vbTextCompare

    ' --- データ追加 ---
    ' Addメソッドを使用: キーが重複するとエラー (実行時エラー 457)
    dict.Add Key:="Apple", Item:=100
    dict.Add Key:="Banana", Item:=150
    Debug.Print "初期状態の要素数: " & dict.Count ' 出力: 2

    ' キーが既に存在するかチェックしてから追加
    If Not dict.Exists("Orange") Then
        dict.Add Key:="Orange", Item:=200
    End If
    Debug.Print "Orange追加後の要素数: " & dict.Count ' 出力: 3

    ' --- データ取得/更新 ---
    ' Itemプロパティを使用: キーが存在しないとエラー (実行時エラー 9)
    Debug.Print "Appleの価格: " & dict.Item("Apple") ' 出力: 100
    ' ItemプロパティはKeyが存在しない場合、新しい要素として追加される(VBAのDictionaryの特有の挙動)
    dict.Item("Grape") = 300 ' Grapeが新規追加される
    Debug.Print "Grape追加後の要素数: " & dict.Count ' 出力: 4

    ' 既存のItemの更新
    dict.Item("Apple") = 120 ' Appleの価格を更新
    Debug.Print "更新されたAppleの価格: " & dict.Item("Apple") ' 出力: 120

    ' --- キーの存在チェック ---
    Debug.Print "Bananaは存在するか? " & dict.Exists("Banana") ' 出力: True
    Debug.Print "Mangoは存在するか? " & dict.Exists("Mango") ' 出力: False

    ' --- 全てのキーと値の列挙 ---
    Dim vKey As Variant
    For Each vKey In dict.Keys
        Debug.Print "Key: " & vKey & ", Item: " & dict.Item(vKey)
    Next vKey

    ' --- データ削除 ---
    ' Removeメソッド: キーが存在しないとエラー (実行時エラー 5)
    dict.Remove "Banana"
    Debug.Print "Banana削除後の要素数: " & dict.Count ' 出力: 3

    ' 全ての要素を削除
    dict.RemoveAll
    Debug.Print "RemoveAll後の要素数: " & dict.Count ' 出力: 0

    ' --- オブジェクトの解放 ---
    Set dict = Nothing
End Sub

堅牢化と応用例

実用的なコードでは、エラーハンドリングやメモリ管理、アーキテクチャへの配慮が不可欠です。

1. 高速な重複排除と集計

大量データからのユニークな値の抽出や、特定のキーでの集計はDictionaryの得意技です。

Sub FastUniqueAndAggregate()
    Dim dict As Scripting.Dictionary
    Set dict = New Scripting.Dictionary
    dict.CompareMode = vbBinaryCompare ' 常にBinaryCompareを推奨

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets("Sheet1") ' 処理対象シート
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row

    Dim dataRange As Range
    Set dataRange = ws.Range("A2:B" & lastRow) ' ヘッダーを除くデータ範囲 (Key列, Value列)
    Dim cell As Range
    Dim key As Variant, item As Variant

    ' --- 高速化のヒント: 画面更新とイベントを一時停止 ---
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual ' 自動計算を停止

    On Error GoTo ErrorHandler

    For Each cell In dataRange.Rows
        key = CStr(cell.Cells(1, 1).Value) ' Keyを文字列として取得
        item = CLng(cell.Cells(1, 2).Value) ' Itemを数値として取得

        If dict.Exists(key) Then
            ' 既に存在する場合、Itemを集計(例: 合計)
            dict.Item(key) = dict.Item(key) + item
        Else
            ' 存在しない場合、新しいKey-Itemペアを追加
            dict.Add Key:=key, Item:=item
        End If
    Next cell

    ' --- 結果の出力 ---
    Dim outputRow As Long
    outputRow = 2 ' 出力開始行
    ws.Range("D1").Value = "Unique Key" ' ヘッダー
    ws.Range("E1").Value = "Aggregated Value" ' ヘッダー

    For Each key In dict.Keys
        ws.Cells(outputRow, "D").Value = key
        ws.Cells(outputRow, "E").Value = dict.Item(key)
        outputRow = outputRow + 1
    Next key

    Debug.Print "ユニークなキーの数: " & dict.Count

CleanUp:
    Set dict = Nothing
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.Calculation = xlCalculationAutomatic ' 自動計算を再開
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

2. LongPtr と 64bit 環境への配慮

Scripting.Dictionary自体はCOMオブジェクトであり、VBAのビット数に直接依存せず動作します。しかし、VBAでAPIを呼び出してポインタ値をDictionaryのKeyやItemとして扱う場合、32bitと64bit環境でポインタのサイズが異なるため、LongPtr型の利用が必須となります。

LongPtrは、32bit環境ではLong(4バイト)、64bit環境ではLongLong(8バイト)として扱われる特殊な型です。PtrSafeキーワードと共にAPI宣言で使用します。

' 64bit対応のAPI宣言例 (DictionaryのKey/Itemに直接は関係ないが、
' ポインタを扱うVBAコードで必要になるため、知識として提示)
#If VBA7 Then
    Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
    Private Declare PtrSafe Function GetWindowTextLength Lib "user32" (ByVal hWnd As LongPtr) As Long
    Private Declare PtrSafe Function GetWindowText Lib "user32" (ByVal hWnd As LongPtr, ByVal lpString As String, ByVal nMaxCount As Long) As Long
#Else
    Private Declare Function GetActiveWindow Lib "user32" () As Long
    Private Declare Function GetWindowTextLength Lib "user32" (ByVal hWnd As Long) As Long
    Private Declare Function GetWindowText Lib "user32" (ByVal hWnd As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
#End If

Sub UseDictionaryWithHwnd()
    Dim dictHwnd As Scripting.Dictionary
    Set dictHwnd = New Scripting.Dictionary
    dictHwnd.CompareMode = vbBinaryCompare

    Dim hWnd As LongPtr ' ウィンドウハンドルを格納
    hWnd = GetActiveWindow() ' 現在アクティブなウィンドウのハンドルを取得

    If hWnd <> 0 Then
        Dim windowTitle As String
        Dim lenTitle As Long

        lenTitle = GetWindowTextLength(hWnd)
        If lenTitle > 0 Then
            windowTitle = String$(lenTitle, Chr$(0))
            GetWindowText hWnd, windowTitle, lenTitle + 1
            windowTitle = Left$(windowTitle, lenTitle)
        Else
            windowTitle = "[タイトルなし]"
        End If

        ' DictionaryのKeyにhWnd(LongPtr)を、Itemにウィンドウタイトルを格納
        ' LongPtrはVariantとして格納可能
        If Not dictHwnd.Exists(hWnd) Then
            dictHwnd.Add Key:=hWnd, Item:=windowTitle
            Debug.Print "hWnd: " & hWnd & ", Title: " & dictHwnd.Item(hWnd)
        End If
    End If

    Set dictHwnd = Nothing
End Sub

このように、APIから取得したポインタ値(LongPtr)をDictionaryのKeyとして直接利用できます。これにより、ウィンドウハンドルをキーとしてウィンドウ情報を管理するようなシステムを、32bit/64bit両方で堅牢に構築できます。

Scripting.Dictionary 主要プロパティ・メソッド・定数

種別 名称 説明 引数 戻り値
プロパティ Count 辞書内のKey-Itemペアの数を取得します。 なし Long
プロパティ CompareMode キーの比較モードを設定/取得します。vbBinaryCompare, vbTextCompareなど。 Integer (VbCompareMethod) Integer
プロパティ Item 指定したKeyに関連付けられたItemを取得または設定します。Keyが存在しない場合、新しい要素として追加されます。 Key As Variant Variant
プロパティ Key 既存の要素のKeyを変更します。 Key As Variant, NewKey As Variant なし
メソッド Add 指定したKeyItemを追加します。Keyが既に存在すると実行時エラーが発生します。 Key As Variant, Item As Variant なし
メソッド Exists 指定したKeyが辞書内に存在するかどうかをチェックします。 Key As Variant Boolean
メソッド Remove 指定したKeyの要素を削除します。Keyが存在しないと実行時エラーが発生します。 Key As Variant なし
メソッド RemoveAll| 辞書内の全ての要素を削除します。 なし なし
メソッド Keys 辞書内の全てのKeyを含むVariant配列を返します。 なし Variant()
メソッド Items 辞書内の全てのItemを含むVariant配列を返します。 なし Variant()
定数 vbBinaryCompare バイナリ比較モード(大文字小文字を区別)。高速。CompareModeに使用。 なし 0 (Long)
定数 vbTextCompare テキスト比較モード(大文字小文字を区別しない)。低速。CompareModeに使用。 なし 1 (Long)
定数 vbDatabaseCompare| データベース比較モード(VBAでは通常使用しない)。CompareModeに使用。 なし 2 (Long)

ベンチ/検証

Dictionaryの性能を体感するため、簡単なベンチマークを実行します。

計測方法

VBAのTimer関数を用いて、処理前後の時刻差をミリ秒単位で計測します。

Sub MeasurePerformance()
    Dim startTime As Double
    Dim endTime As Double
    Dim i As Long
    Dim numData As Long: numData = 100000 ' 10万件のデータ

    Dim dict As Scripting.Dictionary
    Set dict = New Scripting.Dictionary

    Debug.Print "--- Dictionary性能ベンチマーク (" & numData & "件) ---"

    ' --- CompareMode: vbBinaryCompare ---
    dict.CompareMode = vbBinaryCompare
    Debug.Print "CompareMode: vbBinaryCompare"

    ' Add操作の測定
    startTime = Timer
    For i = 1 To numData
        dict.Add Key:="Key" & i, Item:=i
    Next i
    endTime = Timer
    Debug.Print "  Add " & numData & " items: " & Format(endTime - startTime, "0.000") & " seconds"

    ' Exists操作の測定 (半数を存在するキー、半数を存在しないキーで検索)
    startTime = Timer
    For i = 1 To numData
        If i Mod 2 = 0 Then
            ' 存在するキーを検索
            If Not dict.Exists("Key" & i) Then Stop ' エラーチェック
        Else
            ' 存在しないキーを検索
            If dict.Exists("NonExistentKey" & i) Then Stop ' エラーチェック
        End If
    Next i
    endTime = Timer
    Debug.Print "  Exists " & numData & " times: " & Format(endTime - startTime, "0.000") & " seconds"

    ' Item取得操作の測定
    startTime = Timer
    For i = 1 To numData
        Dim val As Variant
        val = dict.Item("Key" & i)
    Next i
    endTime = Timer
    Debug.Print "  Get Item " & numData & " times: " & Format(endTime - startTime, "0.000") & " seconds"

    dict.RemoveAll ' クリア

    ' --- CompareMode: vbTextCompare ---
    dict.CompareMode = vbTextCompare
    Debug.Print "CompareMode: vbTextCompare"

    ' Add操作の測定
    startTime = Timer
    For i = 1 To numData
        dict.Add Key:="key" & i, Item:=i ' 小文字で追加
    Next i
    endTime = Timer
    Debug.Print "  Add " & numData & " items: " & Format(endTime - startTime, "0.000") & " seconds"

    ' Exists操作の測定 (大文字小文字混合で検索)
    startTime = Timer
    For i = 1 To numData
        If i Mod 2 = 0 Then
            If Not dict.Exists("KEY" & i) Then Stop ' 存在するキーを大文字で検索
        Else
            If Not dict.Exists("key" & i) Then Stop ' 存在するキーを小文字で検索
        End If
    Next i
    endTime = Timer
    Debug.Print "  Exists " & numData & " times: " & Format(endTime - startTime, "0.000") & " seconds"

    Set dict = Nothing
End Sub

テスト観点

  • データ量による性能変化: 1万件、10万件、100万件とnumDataを変更して比較する。データ量が増えても、AddExistsItem操作の1回あたりの時間はほとんど変化しないことを確認。
  • CompareModeによる性能差: vbBinaryComparevbTextCompareで、特にAddExists操作の時間差を比較する。vbTextCompareの方が明らかに遅くなることを確認。
  • 操作の種類: AddExistsItemそれぞれの操作の相対的なコストを把握する。

結果の傾向(例: 10万件のデータ)vbBinaryCompare: Add (0.05秒), Exists (0.04秒), Get Item (0.03秒) – vbTextCompare: Add (0.2秒), Exists (0.15秒) vbTextComparevbBinaryCompareに比べて数倍の遅延が発生することがわかります。これは、文字列比較処理のオーバーヘッドによるものです。

応用例/代替案

応用例

  1. 複数テーブルの結合:
    • Excelシート上の2つのテーブル(例: 顧客マスタと注文履歴)を、共通のキー(顧客IDなど)で突き合わせ、関連データを高速に抽出・集計する。一方のテーブルをDictionaryに読み込んでおけば、もう一方のテーブルをループ処理する際にO(1)で結合相手を検索できます。
  2. 大量ログの重複排除:
    • Webサーバーのアクセスログやシステムのエラーログなど、大量のテキストデータから重複する行(または特定のカラムの組み合わせ)をDictionaryのキーとして利用し、高速にユニークなデータのみを抽出する。
  3. 高速集計:
    • 売上データから「商品コードごとの合計売上」や「支店ごとの平均売上」などを算出する際、Dictionaryのキーに商品コード/支店コードを、アイテムに集計値を格納し、ループしながら加算していくことで、SUMIFSなどのシート関数よりも圧倒的に高速な集計が可能です。

代替案

Dictionaryが最適解でない場合や、利用できない場合の代替策を検討します。

  1. VBA Collection:
    • 利点: 参照設定が不要で、組み込みオブジェクトであるため手軽。
    • 欠点: キー検索は線形探索に近くO(N)のため、大量データではDictionaryより大幅に低速。キーが存在しない場合にItemでアクセスするとエラーになる (Dictionaryは新規追加される) など挙動も異なる。
    • 使い分け: 数百件程度の少量データや、参照設定を絶対に避けたい場合に限定。
  2. ADO Recordset / SQL:
    • 利点: データベースと同様の強力なデータ操作が可能。JOINGROUP BYWHEREなどのSQLクエリをExcelデータに対して直接実行でき、非常に高い柔軟性とパフォーマンスを発揮することがある。特に巨大なデータセット(数十万行以上)に対してはExcel VBAのループ処理より効率的。
    • 欠点: ADOライブラリの参照設定とSQL構文の知識が必要。セットアップがやや複雑。
    • 使い分け: ExcelをRDBMSのように扱いたい場合、SQLスキルがある場合。
  3. Excelワークシート関数:
    • 利点: コード不要、関数をセルに入力するだけで機能する。VLOOKUPMATCHINDEXSUMIFSなど。
    • 欠点: 再計算時のパフォーマンスコストが高い(特に揮発性関数)、複雑なロジックの実装が困難、巨大なシートでは計算が非常に遅くなる。
    • 使い分け: 数千行までのデータ、アドホックな分析、VBAコードを書きたくない場合。
  4. 配列とループ:
    • 利点: VBAの基本中の基本。外部オブジェクトへの依存なし。
    • 欠点: 検索や比較は基本O(N)。ネストしたループはO(N^2)となり、パフォーマンスが劇的に悪化する。
    • 使い分け: データの並び順が重要、少量データ、またはDictionaryが使えない特殊な環境。

まとめ

Scripting.Dictionaryオブジェクトは、VBAにおけるデータ処理のパフォーマンスを飛躍的に向上させる強力なツールです。その高速性の源であるハッシュテーブルの内部動作を理解し、特にCompareModeプロパティをvbBinaryCompareに設定することの重要性を認識することが、最高のパフォーマンスを引き出す鍵となります。

また、単にAddItemを使うだけでなく、Existsによる存在チェック、適切なエラーハンドリング、そしてオブジェクトの明示的な解放など、堅牢なコードを書くための実践的な考慮も不可欠です。LongPtrの概念を理解することで、64bit環境下でのVBAの可能性も広がります。

Dictionaryは大量データの重複排除、高速検索、集計処理といったシナリオで絶大な効果を発揮します。本稿で紹介した知識とテクニックを応用し、VBAのボトルネック解消と開発効率向上に役立ててください。

失敗例→原因→対処

失敗例: DictionaryのKeyに、カスタムクラスのオブジェクトを直接格納しようとした。

' TMyClassというカスタムクラスがあったとして
Dim dict As Scripting.Dictionary
Set dict = New Scripting.Dictionary
Dim obj1 As New TMyClass
obj1.ID = 1
obj1.Name = "Test"

' ここで実行時エラー '457': このキーは既にこのコレクションに関連付けられています。
' または、VBAのバージョンによっては別のエラー、あるいは意図しない挙動になる。
dict.Add obj1, "データ1"

原因: Scripting.DictionaryのKeyはVariant型を許容しますが、内部的にハッシュ値を計算する必要があるため、参照型オブジェクトそのものをKeyとして直接扱うことはできません。VBAはオブジェクトをVariant型として渡すと、そのオブジェクトのデフォルトプロパティの値、またはオブジェクトの文字列表現をKeyとして利用しようと試みる場合があります。しかし、多くの場合これは意図しない結果(予期せぬ衝突)を招くか、上記のようにエラーとなります。VBA.Collectionも同様です。

対処: オブジェクトの一意な識別子(ID、GUID、固有の文字列プロパティなど)をDictionaryのKeyとして使用し、オブジェクト自体はItemとして格納します。

' TMyClassというカスタムクラスがあったとして (ID As Long, Name As String などを持つ)
Dim dict As Scripting.Dictionary
Set dict = New Scripting.Dictionary
dict.CompareMode = vbBinaryCompare

Dim obj1 As New TMyClass
obj1.ID = 1
obj1.Name = "TestObject1"

Dim obj2 As New TMyClass
obj2.ID = 2
obj2.Name = "TestObject2"

' オブジェクトのユニークなIDをKeyとして使用
dict.Add obj1.ID, obj1 ' obj1オブジェクト自体をItemとして格納
dict.Add obj2.ID, obj2 ' obj2オブジェクト自体をItemとして格納

Debug.Print "Key 1 のオブジェクト名: " & dict.Item(1).Name ' 出力: TestObject1

' Keyが存在しない場合のエラーハンドリングも忘れずに
Dim searchID As Long: searchID = 3
If dict.Exists(searchID) Then
    Debug.Print "Key " & searchID & " のオブジェクト名: " & dict.Item(searchID).Name
Else
    Debug.Print "Key " & searchID & " は見つかりませんでした。"
End If

Set dict = Nothing
Set obj1 = Nothing
Set obj2 = Nothing

運用チェックリスト

  • [x] Dictionaryを使用する際は、必ずdict.CompareMode = vbBinaryCompareを設定していますか? (必要に応じて前処理でキーを正規化)
  • [x] 大量データを処理する場合、Application.ScreenUpdating = FalseApplication.EnableEvents = FalseApplication.Calculation = xlCalculationManualで画面更新・イベント・自動計算を一時停止していますか?
  • [x] Dictionaryオブジェクトは使用後にSet dict = Nothingで明示的に解放されていますか?
  • [x] Itemで値を取得する前に、dict.Exists(Key)でKeyの存在を確認し、エラーハンドリングを適切に行っていますか?
  • [x] Keyとして参照型の値(オブジェクトそのものなど)を直接使用していませんか?一意な識別子をKeyとして採用していますか?
  • [x] 64bit環境でのVBA API連携が必要な場合、PtrSafeキーワードやLongPtr型を適切に使用していますか?
  • [x] 処理対象のデータ量とDictionaryによるメモリ使用量を監視し、メモリオーバーランの可能性を評価していますか?

参考リンク

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました