📊連載第15回！初心者のためのExcel VBA入門：配列を返す関数でデータ処理を高速化！🌐

# Excel VBAにおける配列を返す関数の作成と活用テクニック

私はVBAの活用経験を通じて得た知識を整理し、共有する目的で記事を作成しているプログラミング歴1年半になるエンジニアです。前回は、Excel VBAにおけるFunction（関数）の作成と活用テクニックについて詳しく説明しました。今回は、配列を返す関数の作成と活用テクニックについて解説します。特に実務での効率的なデータ処理方法、パフォーマンス最適化、エラーハンドリングに焦点を当て、実践的な活用例を紹介します。

なお、配列の基本概念や基本的な使い方については[第7回: Excel VBAにおける配列とFor Eachの活用](https://qiita.com/CodeLeaf/items/bdd8d488e49086219663)で詳しく解説していますので、そちらをご参照ください。

- [第1回: Excel VBAの基礎知識とセキュリティ設定](https://qiita.com/CodeLeaf/items/2d3e3185a725480fecc3)
- [第2回: Excel VBAの基本操作とオブジェクトの理解](https://qiita.com/CodeLeaf/items/c65d2531908aaf53649d)
- [第3回: Excel VBAにおける変数と定数の基本](https://qiita.com/CodeLeaf/items/3b36eddf7b5a8b5c5d99)
- [第4回: Excel VBAにおけるシート操作の基本とエラー処理](https://qiita.com/CodeLeaf/items/573fb7c61a756aa123ea)
- [第5回: Excel VBAにおける条件分岐](https://qiita.com/CodeLeaf/items/8be52d682baa097a65c1)
- [第6回: Excel VBAにおける繰り返し処理の基本](https://qiita.com/CodeLeaf/items/5bc6c961a090e550bca9)
- [第7回: Excel VBAにおける配列とFor Eachの活用](https://qiita.com/CodeLeaf/items/bdd8d488e49086219663)
- [第8回: Excel VBAにおけるFormulaとValueの使い分けとユーザー入力の取得](https://qiita.com/CodeLeaf/items/ecf312a53f7ede91bce9)
- [第9回: Excel VBAにおけるファイル操作とフォルダ管理の基本](https://qiita.com/CodeLeaf/items/e5520321e760364f6aae)
- [第10回: Excel VBAにおけるFileSystemObjectを活用した高度なファイル操作](https://qiita.com/CodeLeaf/items/a78e9c7dd2b7e68f1d9e)
- [第11回: Excel VBAにおけるFileSystemObjectを活用した高度なファイル操作 応用編](https://qiita.com/CodeLeaf/items/4607db0151dddfb7f458)
- [第12回: Excel VBAにおけるStrConv関数の活用と応用テクニック](https://qiita.com/CodeLeaf/items/4f6358548bced6c047e0)
- [第13回: Excel VBAにおけるワークブックの安全な操作と管理テクニック](https://qiita.com/CodeLeaf/items/cf136898dd41c7dd5d9f)
- [第14回: Excel VBAにおけるFunction（関数）の作成と活用テクニック](https://qiita.com/CodeLeaf/items/a299f465bdcb1957e2be)
- 第15回: Excel VBAにおける配列を返す関数の作成と活用テクニック（本記事）
- [第16回: Excel VBAにおけるコレクションの活用と応用テクニック](https://qiita.com/CodeLeaf/items/6a28c65d5f8d19964664)
- [第17回: Excel VBAにおける辞書型（Dictionary）の活用と応用テクニック](https://qiita.com/CodeLeaf/items/5f85b2029e8d51eaa788)
- [第18回: Excel VBAにおけるEnum型を活用した関数設計と実装テクニック](https://qiita.com/CodeLeaf/items/3e91ef9556799d96aeea)
- [第19回: Excel VBAにおけるユーティリティ関数の作成と活用テクニック](https://qiita.com/CodeLeaf/items/bc156b6a9cadd7b10601)
- [第20回: Excel VBAにおける正規表現を活用したファイル名解析テクニック](https://qiita.com/CodeLeaf/items/86284498dee42aab731e)


## 目次

- [はじめに](#はじめに)
- [配列を返す関数の基本](#配列を返す関数の基本)
- [配列を返す関数の構文](#配列を返す関数の構文)
- [配列の返し方（様々なアプローチ）](#配列の返し方様々なアプローチ)
- [実践的な配列関数の作成例](#実践的な配列関数の作成例)
- [多次元配列を返す関数](#多次元配列を返す関数)
- [配列関数のエラーハンドリング](#配列関数のエラーハンドリング)
- [配列を返す関数のパフォーマンス最適化](#配列を返す関数のパフォーマンス最適化)
- [実務での活用シーン](#実務での活用シーン)
- [まとめと次回予告](#まとめと次回予告)

## はじめに

VBAにおける大量データ処理やデータ分析では、配列の活用が欠かせません。前回の記事では、単一の値を返すFunction（関数）の基本について解説しましたが、今回は複数の値をまとめて扱える「配列を返す関数」について深掘りします。

配列を返す関数を活用することで、複数の値を一度に処理でき、コードの効率性と可読性が大幅に向上します。特に多くのデータを処理する業務アプリケーションでは、処理速度の向上やメモリ使用量の最適化につながります。

本記事では、配列を返す関数の基本的な構文から始め、様々な返し方のテクニック、実践的な活用例、多次元配列の扱い方、エラー処理、そしてパフォーマンス最適化まで詳しく解説します。この知識を身につけることで、より洗練されたVBAプログラムを開発できるようになるでしょう。

## 配列を返す関数の基本

VBAで配列を返す関数は、複数の値をまとめて返す強力な機能です。まずは基本概念について理解しましょう。

### 通常の関数と配列を返す関数の違い

| 特性 | 通常の関数 | 配列を返す関数 |
|------|---------|-------------|
| 戻り値 | 単一の値 | 複数の値（配列） |
| 型指定 | Integer, String, Doubleなど | Variant または 型名() |
| 値の取得 | 変数に直接代入 | 配列変数に代入 |
| 使用例 | `result = MyFunc()` | `myArray = GetArray()` |

### 配列を返すメリット

1. **一度に複数の値を返せる**: 複数の処理結果をまとめて取得できます
2. **データのまとまりを維持**: 関連するデータをグループ化して返せます
3. **コードの効率化**: 複数の関数呼び出しを1回にまとめられます
4. **メモリ効率の向上**: 大量データを効率的に処理できます

## 配列を返す関数の構文

配列を返す関数を定義するには、以下の基本構文を使用します。

```vb
Function 関数名() As Variant
    ' 処理内容
    
    ' 配列を作成
    Dim resultArray() As VariantまたはInteger, String等の型
    ReDim resultArray(サイズ指定)
    
    ' 配列に値を設定
    resultArray(0) = 値1
    resultArray(1) = 値2
    ' ...
    
    ' 配列全体を戻り値として返す
    関数名 = resultArray
End Function
```

### 基本的な例

```vb
' 1から指定数までの整数配列を生成する関数
Function GenerateNumbers(ByVal count As Long) As Variant
    ' 配列の宣言
    Dim numbers() As Long
    Dim i As Long
    
    ' 配列のサイズを設定（0〜count-1の要素）
    ReDim numbers(count - 1)
    
    ' 配列に値を設定
    For i = 0 To count - 1
        ' 1からcountまでの数値を格納
        numbers(i) = i + 1
    Next i
    
    ' 配列全体を戻り値として返す
    GenerateNumbers = numbers
End Function

' 関数の使用例
Sub TestGenerateNumbers()
    Dim myArray As Variant
    Dim i As Long
    
    ' 関数を呼び出して配列を取得
    myArray = GenerateNumbers(5)
    
    ' 結果を表示
    For i = LBound(myArray) To UBound(myArray)
        Debug.Print myArray(i)
    Next i
End Sub
```

:::note info
### 配列を返す関数の戻り値の型について

VBAで配列を返す関数を定義する際、戻り値の型には主に2つの選択肢があります。

1. **Variant型**
    最も柔軟で一般的な方法です。どんな型の配列も返せます。
    ```vb
    Function GetData() As Variant
    ```

2. **特定の型の配列**
    やや厳密ですが、コンパイラによるチェックが利きます。
    ```vb
    Function GetStrings() As String()
    ```

ただし、2つ目の方法は古いExcelバージョンではエラーになる可能性があるため、互換性を考慮する場合は `Variant` 型の使用をお勧めします。
:::

## 配列の返し方

### 1. 標準的な方法（配列作成後に返す）

```vb
' 指定した範囲内の偶数を配列で返す関数（startNumからendNumまでの範囲から偶数のみを抽出）
Function GetEvenNumbers(ByVal startNum As Long, ByVal endNum As Long) As Variant
    Dim tempArray() As Long    ' 一時配列
    Dim resultArray() As Long  ' 結果配列
    Dim i As Long, count As Long
    
    ' 必要な最大サイズの一時配列を作成
    ReDim tempArray(endNum - startNum)
    
    ' 偶数を一時配列に格納
    count = 0
    For i = startNum To endNum
        ' 偶数かどうかをチェック
        If i Mod 2 = 0 Then
            ' 偶数なら配列に追加し、カウンタを増やす
            tempArray(count) = i
            count = count + 1
        End If
    Next i
    
    ' 結果配列のサイズを実際の要素数に調整
    ReDim resultArray(count - 1)
    
    ' 一時配列から結果配列にデータをコピー
    For i = 0 To count - 1
        resultArray(i) = tempArray(i)
    Next i
    
    ' 結果配列を返す
    GetEvenNumbers = resultArray
End Function
```

### 2. Arrayステートメントを使用する方法

```vb
' 指定された月の日数を配列で返す関数（月と年を指定すると、その月の全日付を要素とする配列を生成）
Function GetDaysInMonth(ByVal month As Long, ByVal year As Long) As Variant
    Dim lastDay As Long
    
    ' 月の日数を取得
    lastDay = Day(DateSerial(year, month + 1, 0))
    
    ' 月が有効か確認
    If month < 1 Or month > 12 Then
        ' 空の配列を返す
        GetDaysInMonth = Array()
    ElseIf lastDay = 31 Then
        ' 31日ある月
        GetDaysInMonth = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, _
                              16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31)
    ElseIf lastDay = 30 Then
        ' 30日ある月
        GetDaysInMonth = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, _
                              16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30)
    ElseIf lastDay = 29 Then
        ' うるう年の2月
        GetDaysInMonth = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, _
                              16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29)
    Else
        ' うるう年でない2月
        GetDaysInMonth = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, _
                              16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28)
    End If
End Function
```

:::note info
### Array関数とSplit関数について

VBAでは、配列を簡単に作成・操作できる便利な組み込み関数があります。

1. **Array関数**: 固定値から配列を作成します。
   ```vb
   ' 曜日の配列を作成
   weekdays = Array("月", "火", "水", "木", "金", "土", "日")
   ```

2. **Split関数**: 文字列を区切り文字で分割して配列にします。
   ```vb
   ' カンマ区切りの文字列を配列に変換
   names = Split("田中,佐藤,山田,鈴木", ",")
   ' → names(0)="田中", names(1)="佐藤", ...
   ```

これらの関数は特に固定値の配列や文字列処理で非常に便利です。
:::

## 多次元配列を返す関数

複雑なデータ構造を扱う場合、多次元配列を返す関数が役立ちます。

### 2次元配列を返す関数の例

```vb
' 指定したシートの表データを2次元配列として返す関数
' （シートと範囲を指定すると、その範囲のデータを二次元配列で取得）
Function GetTableData(ByVal ws As Worksheet, ByVal tableRange As String) As Variant
    Dim dataRange As Range
    
    ' エラーハンドリングを設定
    On Error Resume Next
    
    ' 指定された範囲を取得
    Set dataRange = ws.Range(tableRange)
    
    ' エラーチェック
    If Err.Number <> 0 Or dataRange Is Nothing Then
        ' エラーリセット
        On Error GoTo 0
        
        ' 空の配列を返す
        GetTableData = Array()
        Exit Function
    End If
    
    ' 通常のエラーハンドリングに戻す
    On Error GoTo 0
    
    ' 範囲の値を2次元配列として取得
    GetTableData = dataRange.Value
End Function

' 使用例
Sub TestGetTableData()
    Dim tableData As Variant
    Dim i As Long, j As Long
    
    ' テーブルデータを取得
    tableData = GetTableData(Worksheets("データ"), "A1:D10")
    
    ' 結果をチェック
    If IsArray(tableData) Then
        ' 配列のサイズが正しいか確認
        If UBound(tableData, 1) >= LBound(tableData, 1) And _
           UBound(tableData, 2) >= LBound(tableData, 2) Then
           
            ' データを処理（例: Debugウィンドウに表示）
            For i = LBound(tableData, 1) To UBound(tableData, 1)
                Dim rowText As String
                rowText = ""
                
                For j = LBound(tableData, 2) To UBound(tableData, 2)
                    rowText = rowText & tableData(i, j) & vbTab
                Next j
                
                Debug.Print rowText
            Next i
        Else
            Debug.Print "テーブルデータが空です。"
        End If
    Else
        Debug.Print "テーブルデータを取得できませんでした。"
    End If
End Sub
```

## 配列関数のエラーハンドリング

配列を返す関数では、適切なエラーハンドリングが特に重要です。

### 配列関数での主なエラー

1. **配列のサイズが0または負数**: UBound < LBoundの配列は不正です
2. **存在しないインデックスへのアクセス**: 配列の範囲外のインデックスを参照するとエラーになります
3. **未初期化の配列**: Dimだけで初期化していない配列を使用するとエラーになります

### 呼び出し側での配列チェック

配列を返す関数を使用する際は、呼び出し側でも適切なチェックが必要です。

```vb
' 配列関数の結果を安全に処理する例
Sub SafeArrayProcessing()
    Dim results As Variant
    Dim i As Long
    
    ' 配列を取得
    results = GetSomeArray()
    
    ' 配列かどうかをチェック
    If Not IsArray(results) Then
        MsgBox "配列が返されませんでした。", vbExclamation
        Exit Sub
    End If
    
    ' 空の配列かどうかをチェック（エラー防止のため On Error を使用）
    On Error Resume Next
    i = LBound(results)
    
    If Err.Number <> 0 Then
        ' LBound でエラーが発生した場合は空の配列
        On Error GoTo 0
        MsgBox "返された配列は空です。", vbInformation
        Exit Sub
    End If
    
    ' 通常のエラーハンドリングに戻す
    On Error GoTo 0
    
    ' 配列の要素数をチェック
    If UBound(results) < LBound(results) Then
        MsgBox "配列に要素がありません。", vbInformation
        Exit Sub
    End If
    
    ' ここから安全に配列を処理できる
    For i = LBound(results) To UBound(results)
        ' 配列の要素を処理
        Debug.Print "要素 " & i & ": " & results(i)
    Next i
End Sub
```

:::note info
### IsArrayEmpty関数

頻繁に配列のチェックを行う場合は、以下のような関数を作成すると便利です。

```vb
' 配列が空かどうかをチェックする関数
Function IsArrayEmpty(arr As Variant) As Boolean
    ' 配列でない場合はTrueを返す
    If Not IsArray(arr) Then
        IsArrayEmpty = True
        Exit Function
    End If
    
    ' エラーハンドリングを設定
    On Error Resume Next
    
    ' LBoundを試す（エラーになれば空の配列）
    Dim temp As Long
    temp = LBound(arr)
    
    If Err.Number <> 0 Then
        ' エラーがあれば空の配列
        IsArrayEmpty = True
    Else
        ' UBound < LBoundなら空の配列
        IsArrayEmpty = (UBound(arr) < LBound(arr))
    End If
    
    ' 通常のエラーハンドリングに戻す
    On Error GoTo 0
End Function
```

この関数を使えば、配列のチェックが簡潔になります。
```vb
If IsArrayEmpty(results) Then
    MsgBox "データがありません"
    Exit Sub
End If
```
:::

## 配列を返す関数のパフォーマンス最適化

大量のデータを処理する際には、パフォーマンスが重要な課題となります。

### 1. 適切な配列サイズの事前確保

```vb
' 効率的な配列サイズ確保の例（元データから特定条件に合う行だけを抽出し二次元配列で返す関数）
' 引数: sourceData(元データの二次元配列), filterColumn(フィルタする列番号), filterValue(フィルタ条件値)
Function GetFilteredData(ByVal sourceData As Variant, ByVal filterColumn As Long, _
                        ByVal filterValue As Variant) As Variant
                        
    Dim resultArray() As Variant ' 結果を格納する配列
    Dim rowCount As Long
    Dim colCount As Long
    Dim resultCount As Long
    Dim i As Long, j As Long
    
    ' 配列のサイズを取得
    rowCount = UBound(sourceData, 1) - LBound(sourceData, 1) + 1
    colCount = UBound(sourceData, 2) - LBound(sourceData, 2) + 1
    
    ' 結果配列を最大サイズで初期化（最適化ポイント）
    ReDim resultArray(1 To rowCount, 1 To colCount)
    resultCount = 0
    
    ' データをフィルタリング
    For i = LBound(sourceData, 1) To UBound(sourceData, 1)
        ' フィルタ条件をチェック
        If sourceData(i, filterColumn) = filterValue Then
            ' 一致する行をカウント
            resultCount = resultCount + 1
            
            ' データを結果配列にコピー
            For j = LBound(sourceData, 2) To UBound(sourceData, 2)
                resultArray(resultCount, j) = sourceData(i, j)
            Next j
        End If
    Next i
    
    ' 結果がない場合
    If resultCount = 0 Then
        GetFilteredData = Array()
        Exit Function
    End If
    
    ' 実際のサイズに合わせて最終配列を作成
    Dim finalArray() As Variant
    ReDim finalArray(1 To resultCount, 1 To colCount)
    
    ' 最終配列にデータをコピー
    For i = 1 To resultCount
        For j = 1 To colCount
            finalArray(i, j) = resultArray(i, j)
        Next j
    Next i
    
    ' 結果配列を返す
    GetFilteredData = finalArray
End Function
```

### 2. Worksheetの値を一度に取得

```vb
' シートデータを効率的に処理する関数
Function ProcessSheetData(ByVal ws As Worksheet, ByVal headerRow As Long) As Variant

    Dim dataRange As Range
    Dim lastRow As Long, lastCol As Long
    Dim allData As Variant
    Dim result() As Variant
    Dim i As Long, validCount As Long
    
    ' データ範囲を決定
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    lastCol = ws.Cells(headerRow, ws.Columns.Count).End(xlToLeft).Column
    
    ' データがない場合
    If lastRow <= headerRow Then
        ProcessSheetData = Array()
        Exit Function
    End If
    
    ' データ範囲を設定
    Set dataRange = ws.Range(ws.Cells(headerRow + 1, 1), ws.Cells(lastRow, lastCol))
    
    ' 全データを一度に取得（パフォーマンス向上の重要ポイント）
    allData = dataRange.Value
    
    ' 処理結果用の配列を確保
    ReDim result(LBound(allData, 1) To UBound(allData, 1))
    validCount = 0
    
    ' データ処理（例: 各行の平均値を計算）
    For i = LBound(allData, 1) To UBound(allData, 1)
        Dim rowSum As Double
        Dim colCount As Long
        Dim j As Long
        
        rowSum = 0
        colCount = 0
        
        ' 行内の数値を合計
        For j = LBound(allData, 2) To UBound(allData, 2)
            If IsNumeric(allData(i, j)) Then
                rowSum = rowSum + CDbl(allData(i, j))
                colCount = colCount + 1
            End If
        Next j
        
        ' 数値データがある場合のみ平均を計算
        If colCount > 0 Then
            validCount = validCount + 1
            result(validCount) = rowSum / colCount
        End If
    Next i
    
    ' 有効なデータがない場合
    If validCount = 0 Then
        ProcessSheetData = Array()
        Exit Function
    End If
    
    ' 結果配列のサイズを調整
    ReDim Preserve result(1 To validCount)
    
    ' 結果配列を返す
    ProcessSheetData = result
End Function
```


:::note warn
### パフォーマンス最適化のベストプラクティス

1. **ワークシートとの頻繁なやり取りを避ける**
   ワークシートから一度にデータを取得し、VBAのメモリ内で処理しましょう。
   ```vb
   ' 非効率な方法（避けるべき）
   For i = 1 To 1000
       For j = 1 To 10
           value = Cells(i, j).Value  ' 各セルに個別にアクセス
           ' 処理...
       Next j
   Next i
   
   ' 効率的な方法
   data = Range("A1:J1000").Value  ' 一度にデータを取得
   For i = 1 To 1000
       For j = 1 To 10
           value = data(i, j)  ' メモリ内のデータを使用
           ' 処理...
       Next j
   Next i
   ```

2. **画面更新の一時停止**
   大量の処理を行う前に画面更新を停止し、処理後に再開すると高速化できます。
   ```vb
   Application.ScreenUpdating = False
   ' 処理...
   Application.ScreenUpdating = True
   ```

3. **計算モードの一時変更**
   計算を手動に設定することで、処理中の自動再計算を防げます。
   ```vb
   Dim calcMode As XlCalculation
   calcMode = Application.Calculation
   Application.Calculation = xlCalculationManual
   ' 処理...
   Application.Calculation = calcMode
   ```

4. **Variant型より特定の型を使用**
   可能な限り、Variant型ではなく特定の型（Long, Double, Stringなど）を使用しましょう。型変換のオーバーヘッド（プログラムが実行されるときに余計にかかる処理や時間）が減少します。
:::

## 実践的な配列関数の作成例

### 例1: 指定条件に一致するセルの値を配列で返す関数

```vb
' 指定した条件に一致するセルの値を配列で返す関数（範囲と条件を指定すると、条件を満たすセル値の一次元配列を返す）
' 引数: targetRange(検索範囲), condition(条件式、例: ">100"、"<>0"、"Like *ABC*")
Function FilterCellsByCondition(ByVal targetRange As Range, ByVal condition As String) As Variant
    Dim result() As Variant
    Dim cell As Range
    Dim count As Long
    Dim tempResult() As Variant
    Dim i As Long
    
    ' 一時的な結果配列を十分なサイズで初期化
    ReDim tempResult(1 To targetRange.Cells.Count)
    count = 0
    
    ' 各セルをチェック
    For Each cell In targetRange
        ' 条件式を評価（条件の例: ">100"、"<>0"、"Like *ABC*"など）
        On Error Resume Next
        If Evaluate(cell.Value & condition) Then
            ' カウンタを増加
            count = count + 1
            ' 条件に一致する値を一時配列に格納
            tempResult(count) = cell.Value
        End If
        On Error GoTo 0
    Next cell
    
    ' 結果がない場合は空の配列を返す
    If count = 0 Then
        FilterCellsByCondition = Array()
        Exit Function
    End If
    
    ' 実際のサイズに合わせて結果配列を作成
    ReDim result(1 To count)
    
    ' 一時配列から結果配列にデータをコピー
    For i = 1 To count
        result(i) = tempResult(i)
    Next i
    
    ' 結果配列を返す
    FilterCellsByCondition = result
End Function

' 使用例
Sub TestFilterCells()
    Dim results As Variant
    Dim i As Long
    
    ' A1:A10の範囲から100より大きい値を取得
    results = FilterCellsByCondition(Range("A1:A10"), ">100")
    
    ' 結果を表示
    If IsArray(results) Then
        If UBound(results) >= LBound(results) Then
            For i = LBound(results) To UBound(results)
                Debug.Print results(i)
            Next i
        Else
            Debug.Print "条件に一致する値はありません。"
        End If
    Else
        Debug.Print "結果が配列ではありません。"
    End If
End Sub
```

:::note info
### Evaluate関数について

`Evaluate`関数はExcel VBAで数式や条件式を動的に評価するための強力な関数です。この関数を使うと、文字列として表現された数式や条件をVBAの中で実行することができます。

#### 基本的な使い方
```vb
result = Evaluate("A1+B1")        ' A1とB1のセル値を足した結果が返される
result = Evaluate("SUM(A1:A10)")  ' A1からA10までの合計が返される
```

#### 条件式との組み合わせ
`FilterCellsByCondition`関数の例では、`Evaluate(cell.Value & condition)`というコードが使われています。これにより、セルの値とユーザーが指定した条件（例："<100"、">0"、"<>0"など）を組み合わせた式を動的に評価できます。

#### 主な特徴
1. 実行時に数式や条件式を評価できる
2. Excelの組み込み関数をVBA内で利用できる
3. セル参照や範囲を動的に操作できる

#### 注意点使える
- 構文エラーがある場合は実行時エラーが発生するため、`On Error Resume Next`などのエラーハンドリングが重要
- セル参照（A1など）はアクティブシートの値を参照するため、適切なシートがアクティブであることを確認する必要がある

実務では、ユーザーが入力した条件式を動的に適用したい場合や、複雑な条件フィルタリングを行う場合に特に便利です。
:::

### 例2: データの一括検索とフィルタリング

```vb
' 指定した検索語に一致する行全体を配列で返す関数
' 引数: ws(検索対象シート), searchColumn(検索する列), searchText(検索語), caseSensitive(大文字小文字区別)
Function SearchRowsContaining(ByVal ws As Worksheet, ByVal searchColumn As Long, _
    ByVal searchText As String, ByVal caseSensitive As Boolean) As Variant
    
    Dim dataRange As Range        ' 検索結果の格納する変数
    Dim lastRow As Long
    Dim i As Long, matchCount As Long
    Dim tempResults() As Variant  ' 検索結果を一時的に保存する配列
    Dim finalResults() As Variant ' 最終的な結果を格納する配列
    
    ' シートの最終行を取得
    lastRow = ws.Cells(ws.Rows.Count, searchColumn).End(xlUp).Row
    
    ' 検索対象の範囲を設定
    Set dataRange = ws.Range(ws.Cells(1, 1), ws.Cells(lastRow, ws.Columns.Count).End(xlToLeft))
    
    ' 最大で全行を格納できる一時配列を作成
    ReDim tempResults(1 To lastRow, 1 To dataRange.Columns.Count)
    matchCount = 0
    
    ' 各行をチェック
    For i = 1 To lastRow
        Dim cellValue As String   ' セルの値を保存する変数
        Dim compareText As String ' 比較用のテキストを保存する変数
        Dim searchFor As String   ' 検索する文字列を保存する変数
        
        ' セルの値を文字列として取得
        cellValue = CStr(ws.Cells(i, searchColumn).Value)
        
        ' 大文字/小文字の区別
        If caseSensitive Then
            compareText = cellValue
            searchFor = searchText
        Else
            compareText = LCase(cellValue)
            searchFor = LCase(searchText)
        End If
        
        ' 検索テキストが含まれているか確認
        If InStr(compareText, searchFor) > 0 Then
            matchCount = matchCount + 1
            
            ' 行全体のデータを一時配列にコピー
            Dim j As Long
            For j = 1 To dataRange.Columns.Count
                tempResults(matchCount, j) = ws.Cells(i, j).Value
            Next j
        End If
    Next i
    
    ' 一致するものがない場合は空の配列を返す
    If matchCount = 0 Then
        SearchRowsContaining = Array()
        Exit Function
    End If
    
    ' 実際の結果数に合わせて最終配列を作成
    ReDim finalResults(1 To matchCount, 1 To dataRange.Columns.Count)
    
    ' 一時配列から最終配列にデータをコピー
    For i = 1 To matchCount
        Dim k As Long
        For k = 1 To dataRange.Columns.Count
            finalResults(i, k) = tempResults(i, k)
        Next k
    Next i
    
    ' 結果配列を返す
    SearchRowsContaining = finalResults
End Function

' 使用例
Sub TestSearchRows()
    Dim results As Variant
    Dim i As Long, j As Long
    
    ' "顧客" という単語を含む行を検索（大文字/小文字を区別しない）
    results = SearchRowsContaining(Worksheets("データ"), 2, "顧客", False)
    
    ' 結果を表示
    If IsArray(results) Then
        If UBound(results, 1) >= LBound(results, 1) Then
            ' 結果を別シートに表示
            Dim outputSheet As Worksheet
            Set outputSheet = Worksheets.Add
            
            ' 各行をシートにコピー
            For i = LBound(results, 1) To UBound(results, 1)
                For j = LBound(results, 2) To UBound(results, 2)
                    outputSheet.Cells(i, j).Value = results(i, j)
                Next j
            Next i
            
            outputSheet.Cells(1, 1).Select
        Else
            MsgBox "検索条件に一致するデータはありません。", vbInformation
        End If
    End If
End Sub
```

## まとめ

Excel VBAにおける配列を返す関数は、大量データの処理や複雑なデータ構造の取り扱いを効率化する非常に強力なテクニックです。この記事では、配列を返す関数の基本構文から始まり、様々な配列の返し方、多次元配列の取り扱い、適切なエラーハンドリング、パフォーマンス最適化テクニック、そして実践的な関数の作成例まで詳しく解説しました。これらの知識を身につけることで、より効率的で堅牢なVBAプログラムの開発が可能になります。

これらの配列関数テクニックを、以前に解説した条件分岐、繰り返し処理、通常の関数、ワークブック操作などと組み合わせることで、より高度で実用的なExcel VBAアプリケーションを開発することができます。例えば、大量データの高速な分析処理、複雑なフィルタリング操作、多次元データの効率的な操作など、今回紹介した技術を応用することで、処理速度が向上し、メモリ効率の良いプログラムの構築が可能です。

もし記事の内容で不明な点や、より詳しく知りたい部分がありましたら、コメントでお知らせください。また、実務での配列関数の活用例や、より効率的な実装方法など、皆様のノウハウもぜひ共有していただければ幸いです。

次回の記事では、Excel VBAにおけるコレクションの活用について解説します。配列と同様にデータをグループ化して扱えるコレクションの特性と利点を理解し、より柔軟で高機能なVBAプログラミングを実現する方法を学んでいきましょう。ぜひご期待ください！