I just got around to creating this pseudo-COUNTIFS approach based largely on your existing routine
Sub PseudoCountifs()
Const sPROCEDURE_NAME = "PseudoCountIfs"
Dim dStartTime As Double, dStopTime As Double, dColumnTime As Double, dCountIfStart As Double
Dim rngWhat As Range, rngWhere As Range, rngResult As Range
Dim lRow As Long, lCol As Long, lWhatLastRow As Long, lWhatLastCol As Long, lWhereLastRow As Long
Dim avWhat As Variant, avWhere As Variant, avResult As Variant
Application.ScreenUpdating = False
lWhatLastRow = ControlsSheet.[WhatLastRow]
lWhatLastCol = ControlsSheet.[WhatLastCol]
lWhereLastRow = ControlsSheet.[WhereLastRow]
With DataSheet
Set rngWhat = .Range(.Cells(1, 1), .Cells(lWhatLastRow, lWhatLastCol))
Set rngWhere = .Range(.Cells(1, 1), .Cells(lWhereLastRow, lWhatLastCol)).Offset(0, lWhatLastCol)
Set rngResult = .Range(.Cells(1, 1), .Cells(lWhatLastRow, 2)).Offset(0, 1 + lWhatLastCol * 2)
End With
ReDim avWhat(1 To rngWhat.Rows.Count)
ReDim avWhere(1 To rngWhere.Rows.Count)
avResult = avWhat
For lRow = LBound(avWhat) To UBound(avWhat) Step 1
avWhat(lRow) = Join(Application.Transpose(Application.Transpose(rngWhat.Rows(lRow))), "^")
Next lRow
For lRow = LBound(avWhere) To UBound(avWhere) Step 1
avWhere(lRow) = Join(Application.Transpose(Application.Transpose(rngWhere.Rows(lRow))), "^")
Next lRow
Set rngWhere = rngWhere.Offset(, rngWhere.Columns.Count).Resize(, 1)
rngWhere.Value = Application.Transpose(avWhere)
With rngResult
.Clear
.Columns(1).Value = Application.Transpose(avWhat)
End With
dStartTime = Timer
dCountIfStart = Timer
With WorksheetFunction
For lRow = LBound(avWhat) To UBound(avWhat)
If avWhat(lRow) <> Empty Then
avResult(lRow) = .CountIf(rngWhere, avWhat(lRow))
Else
avResult(lRow) = 0
End If
Next lRow
End With
Debug.Print sPROCEDURE_NAME & " CountIf in: " & TimeConvert(Timer - dCountIfStart)
rngResult.Columns(2) = Application.Transpose(avResult)
dStopTime = Timer
Debug.Print sPROCEDURE_NAME & " done in: " & TimeConvert(dStopTime - dStartTime)
Application.ScreenUpdating = True
MsgBox sPROCEDURE_NAME & " done in: " & TimeConvert(dStopTime - dStartTime)
End Sub
takes around 4 seconds to process 1000 calculations based on 40000 x 6 matrix (and 6 criteria)
Bookmarks