【VBAリファレンス】エクセル練習問題最長連続出現数(ランレングス)の算出

スポンサーリンク

エクセル練習問題:最長連続出現数(ランレングス)の算出とVBAによる実装

データの分析や品質管理の現場において、「ある事象が最大で何回連続して発生したか」という指標は非常に重要です。例えば、製造ラインにおける不良品の連続発生数や、Webサイトにおけるユーザーの連続ログイン日数、あるいは株価の連続上昇局面の把握など、その用途は枚挙に暇がありません。

Excelの標準関数のみでこれを計算しようとすると、配列数式や複雑なIF関数のネストを駆使する必要があり、可読性やメンテナンス性が著しく低下します。本稿では、プロフェッショナルな視点から、この「ランレングス(Run-Length)」をVBAを用いて効率的かつ堅牢に算出する手法を詳説します。

ランレングス算出のアルゴリズムと論理的アプローチ

ランレングスとは、同一の値が連続して続く回数を意味します。最長連続出現数(Maximum Run-Length)を求めるためには、データ列を先頭から順に走査し、以下のロジックを実装する必要があります。

1. 現在の値を保持する変数(CurrentValue)と、現在の連続回数を保持する変数(CurrentCount)を初期化する。
2. 最大連続回数を保持する変数(MaxCount)を用意する。
3. リストの各行をループ処理し、直前の値と比較する。
4. 値が一致すれば、CurrentCountをインクリメント(+1)する。
5. 値が不一致であれば、CurrentCountを1にリセットし、CurrentValueを新しい値に更新する。
6. インクリメントの直後に、常にCurrentCountとMaxCountを比較し、CurrentCountの方が大きければMaxCountを更新する。

このアルゴリズムの計算量はO(n)であり、データ量に対して線形時間で処理が完了するため、Excelの再計算負荷を抑えつつ高速に結果を得ることが可能です。

VBAによる実装:汎用的なプロシージャの作成

以下に、指定した範囲内のデータから最長連続出現数を算出する汎用的な関数コードを示します。このコードは、引数としてセル範囲を受け取り、Long型の値を返す設計にしています。


Option Explicit

' 指定された範囲の最長連続出現数を算出する関数
Public Function GetMaxRunLength(targetRange As Range) As Long
    Dim cell As Range
    Dim prevValue As Variant
    Dim currentCount As Long
    Dim maxCount As Long
    Dim isFirst As Boolean
    
    ' 初期化
    currentCount = 0
    maxCount = 0
    isFirst = True
    
    ' 範囲内の各セルを走査
    For Each cell In targetRange
        ' 空セルはスキップするか、あるいは終了条件とするか要件に合わせて調整
        If IsEmpty(cell.Value) Then GoTo ContinueLoop
        
        If isFirst Then
            prevValue = cell.Value
            currentCount = 1
            maxCount = 1
            isFirst = False
        Else
            If cell.Value = prevValue Then
                ' 値が一致する場合、カウントアップ
                currentCount = currentCount + 1
            Else
                ' 値が不一致の場合、カウントをリセット
                currentCount = 1
                prevValue = cell.Value
            End If
        End If
        
        ' 最大値の更新
        If currentCount > maxCount Then
            maxCount = currentCount
        End If
        
ContinueLoop:
    Next cell
    
    GetMaxRunLength = maxCount
End Function

' 実行用テストプロシージャ
Public Sub TestRunLength()
    Dim rng As Range
    Set rng = Range("A1:A20") ' 算出対象範囲
    
    Dim result As Long
    result = GetMaxRunLength(rng)
    
    MsgBox "最長連続出現数は " & result & " 回です。", vbInformation
End Sub

コードの詳細解説と設計の意図

上記のコードは、単に動くことだけを目的とせず、実務での堅牢性を意識した実装となっています。

まず、`isFirst` フラグの採用です。最初の要素と2番目以降の要素を同一のループ内で比較しようとすると、初回の比較対象が存在しないためエラーになります。このフラグを用いることで、ループ構造をシンプルに保ちつつ、初回のみ特別な初期化処理を行うことが可能です。

次に、`GoTo ContinueLoop` を用いた空セルのスキップ処理です。データの中途に空白セルが混入している場合、それを「値の断絶」とみなすか「無視」するかはビジネスロジックに依存します。今回は柔軟性を考慮し、空セルをスキップして連続性を判定する仕様にしていますが、要件に応じて `Exit For` に変更することで「空セルが出現した時点で計算を終了する」という挙動にも簡単に変更可能です。

最後に、`Variant` 型の活用です。データ型を `String` や `Double` に固定せず `Variant` にすることで、数値、文字列、日付など、どのようなデータ型の列に対しても同一の関数で対応できる「ポリモーフィズム的な柔軟性」を持たせています。

実務での活用とパフォーマンスチューニング

実務の現場では、データ量が数万行に及ぶことも珍しくありません。その場合、`For Each` ループでセルオブジェクトに直接アクセスすると、Excelのオーバーヘッドにより処理が遅延します。

10万行を超えるような大規模データを扱う場合は、以下のような最適化を検討してください。

・配列への一括転送:`Dim arr As Variant` とし、`arr = targetRange.Value` によってセル範囲を一気にメモリ上の配列に読み込みます。配列の要素に対してループを回すことで、セルアクセスを排除し、処理速度を数十倍から数百倍に向上させることが可能です。
・画面更新の停止:`Application.ScreenUpdating = False` および `Application.Calculation = xlCalculationManual` を設定することで、VBA実行中の不要な再計算や描画を抑制し、パフォーマンスを最大化できます。

また、エラーハンドリングについても留意が必要です。もし範囲内にエラー値(#N/Aや#VALUE!など)が含まれている場合、`cell.Value` での比較がエラーを吐く可能性があります。`IsError(cell.Value)` 関数を用いて、エラー値が含まれている場合は無視するか、あるいはエラー値を検知して警告を出すようなロジックを追加することで、システムとしての安定性が格段に向上します。

まとめ

最長連続出現数の算出は、一見単純な問題ですが、その裏側にはデータ構造への理解と、効率的なアルゴリズムの設計思想が凝縮されています。標準関数で苦労して数式を組み立てるよりも、今回紹介したようなVBAによるロジックの実装を選択することで、以下のメリットを享受できます。

1. 再利用性:一度作成した関数は、モジュールとして保存することで他のブックでもすぐに利用可能です。
2. 可読性:コード化することで「何をしているか」が明確になり、後任のエンジニアが修正を行う際も迷うことがありません。
3. 拡張性:特定の条件(例:連続する値が「0」である場合のみカウントする、など)を追加する際、VBAであれば条件分岐を一つ加えるだけで対応できます。

Excel VBAは単なる自動化ツールではなく、データ処理のアルゴリズムを構築するための強力なプラットフォームです。このランレングスの実装を通じて、ぜひ「ロジックをコードに落とし込む」というプログラミングの醍醐味を体感し、日々の業務効率化に役立ててください。どのような複雑なデータ分析の要求であっても、基礎となるアルゴリズムを正しく理解していれば、必ず最適解を導き出すことができます。

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