ExcelでMAXIFとMINIFを使う(高速化)

昨年のExcelでMAXIFとMINIFを使うで掲載したオリジナルの関数「MAXIF」と「MINIF」ですが、再度実業務で触る機会があり、その際に高速化を行いましたので再掲載しておきます(旧MAXIFや旧MINIFとの互換性はあるので、関数内の差し替えだけで使用できます)。
 
以前と同じく、SUMIF的な感じで指定範囲の最大値or最小値を返す関数です。縦方向への使用にしか対応していません。
 
※なお、エクセルのセル内計算式でMAXIFやMINIFをしたい場合は、「=MAX(IF(A1:A6=1,B1:B6))」「=MIN(IF(A1:A6=1,B1:B6))」のようなやり方もあるそうです(入力確定時にCtrl+Shift+Enterする必要有り)
 
MAXIF関数

Function MAXIF(ScanCells As Range, _
               KeyWord As Variant, _
               CalcCells As Range) As Variant
    ' 条件付きMax関数
    Dim Y As Long
    Dim MaxVal As Variant
    Dim ChkVal As Range
    Dim CmpVal As Variant
    Dim CmpRows As Long
    
    ' 高速化のためセル関係の情報を変数へ取り込む
    CmpVal = CalcCells
    CmpRows = CalcCells.Rows.Count
    
    ' 比較用初期値
    MaxVal = ""
    
    Y = 1
    For Each ChkVal In ScanCells
      If ChkVal.Value = KeyWord Then
        If Y <= CmpRows Then
          If Not IsNull(CmpVal(Y, 1)) Then
            If CmpVal(Y, 1) <> "" Then
              If MaxVal = "" Or _
                 MaxVal < CmpVal(Y, 1) Then
                  MaxVal = CmpVal(Y, 1)
              End If
            End If
          End If
        End If
      End If
      Y = Y + 1
    Next ChkVal
    
    If MaxVal <> "" Then
        MAXIF = MaxVal
    Else
        MAXIF = ""
    End If
End Function

 
MINIF関数

Function MINIF(ScanCells As Range, _
               KeyWord As Variant, _
               CalcCells As Range) As Variant
    ' 条件付きMin関数
    Dim Y As Long
    Dim MinVal As Variant
    Dim ChkVal As Range
    Dim CmpVal As Variant
    Dim CmpRows As Long
    
    ' 高速化のためセル関係の情報を変数へ取り込む
    CmpVal = CalcCells
    CmpRows = CalcCells.Rows.Count
    
    ' 比較用初期値
    MinVal = ""
    
    Y = 1
    For Each ChkVal In ScanCells
      If ChkVal.Value = KeyWord Then
        If Y <= CmpRows Then
          If Not IsNull(CmpVal(Y, 1)) Then
            If CmpVal(Y, 1) <> "" Then
              If MinVal = "" Or _
                 MinVal > CmpVal(Y, 1) Then
                  MinVal = CmpVal(Y, 1)
              End If
            End If
          End If
        End If
      End If
      Y = Y + 1
    Next ChkVal
    
    If MinVal <> "" Then
        MINIF = MinVal
    Else
        MINIF = ""
    End If
End Function

 
それぞれ、ScanCellsに比較対象のセル(単列複数行)、KeyWordにScanCellsから選択するデータ(文字列等)、CalcCellsにMax/Min判定対象のセル(単列複数行)を指定。
「=MAXIF(A2:A12, "合計", B2:B12)」とすると、A列が"合計"の行のB列のうち最大の値が返るというイメージ。
 
今回の修正で、ループをfor each 化したり処理前にセル情報を変数へ転送するなどして高速化しています。以前hiyori.net様で高速化のヒントを頂いていたのでそちらを参考にさせて頂いてます。感謝です。
 
多段のIFは条件一致のチェックですが、若干厳重に組んでいるので、使用条件によってはもっと簡略化することで高速化が図れると思います(ヌルチェックを飛ばしたり、1行のIF文にまとめてしまったり)。
 
あとは煮るなり焼くなりお好きにどうぞ〜。