Here's one approach - first count (and collect) the matching rows, then resize and fill your array.
EDIT: updated to push the array filtering into a standalone function which accepts the name of the function to be used when filtering each row.
Sub TestArrayFiltering()
Dim myTable As ListObject
Dim myArray As Variant, ws As Worksheet, filtered
Set ws = ActiveSheet
Set myTable = ws.ListObjects("accounts_table")
myArray = myTable.DataBodyRange
'filter the array according to the function "MyRowmatch"
filtered = Filter2DArray(myArray, "MyRowMatch")
If Not IsEmpty(filtered) Then
ws.Range("I2").Resize(UBound(filtered, 1), UBound(filtered, 2)).Value = filtered
Else
MsgBox "No matches"
End If
End Sub
'do we want this "row" ?
Function MyRowMatch(arr, indx) As Boolean
Dim v
v = arr(indx, 4)
MyRowMatch = (arr(indx, 5) = "On" And v <> "T" And v <> "I")
End Function
'Utility function: take a 2-d array and return a new array containing only rows which
' return True from the function named in `func`
' `func` must take 2 arguments - a 2D array and a row index
Function Filter2DArray(arrIn, func As String)
Dim arrOut As Variant, matches As New Collection
Dim x, col As Long, i As Long
Dim lbr As Long, lbc As Long, ubr As Long, ubc As Long
lbr = LBound(arrIn, 1) 'get input array bounds
lbc = LBound(arrIn, 2)
ubr = UBound(arrIn, 1)
ubc = UBound(arrIn, 2)
For x = lbr To ubr 'collect matching row indexes
If Application.Run(func, arrIn, x) Then matches.Add x
Next x
'resize destination array and transfer matching rows
If matches.Count > 0 Then
ReDim arrOut(lbr To matches.Count + (lbr - 1), lbc To ubc)
i = lbr
For Each x In matches
For col = lbc To ubc
arrOut(i, col) = arrIn(x, col)
Next col
i = i + 1
Next x
Filter2DArray = arrOut
Else
Filter2DArray = Empty
End If
End Function
WorksheetFunction.CountIfs.ReDimis expensive and shouldn't be done inside a loop. But more importantly,ReDim Preserveonly allows one to modify the last array dimension, so it wouldn't work with your current array setup.