This is the function I've wrote to filter a two-dimension array. I use it mainly on forms with user-defined filter (categories, dates, search bar, etc). It works fine, but it's ugly. Do you have any advice?
Function FilterArray(ByVal originalArray As Variant, _
Optional arrayOfColumnToReturn As Variant, _
Optional firstExactMatchColumn As Integer = -1, Optional firstExactMatchValue As Variant, _
Optional secondExactMatchColumn As Integer = -1, Optional secondExactMatchValue As Variant, _
Optional thirdExactMatchColumn As Integer = -1, Optional thirdExactMatchValue As Variant, _
Optional firstColumnToExclude As Integer = -1, Optional firstValueToExclude As Variant, _
Optional secondColumnToExclude As Integer = -1, Optional secondValueToExclude As Variant, _
Optional thirdColumnToExclude As Integer = -1, Optional thirdValueToExclude As Variant, _
Optional firstColumnIsBetween As Integer = -1, Optional firstLowValue As Variant, Optional firstHighValue As Variant, _
Optional secondColumnIsBetween As Integer = -1, Optional secondLowValue As Variant, Optional secondHighValue As Variant, _
Optional thirdColumnIsBetween As Integer = -1, Optional thirdLowValue As Variant, Optional thirdHighValue As Variant, _
Optional partialMatchColumnsArray As Variant = -1, Optional partialMatchValue As Variant) As Variant
FilterArray = -1
If Not IsArray(originalArray) Then Exit Function
Dim firstRow As Long
Dim lastRow As Long
Dim firstColumn As Long
Dim lastColumn As Long
Dim row As Long
Dim col As Long
Dim filteredArrayRow As Long
Dim partialCol As Long
firstRow = LBound(originalArray, 1)
lastRow = UBound(originalArray, 1)
firstColumn = LBound(arrayOfColumnToReturn)
lastColumn = UBound(arrayOfColumnToReturn)
' If the caller don't pass the array of column to return I create an array with all the columns and I preserve the order
If Not IsArray(arrayOfColumnToReturn) Then
ReDim arrayOfColumnToReturn(LBound(originalArray, 2) To UBound(originalArray, 2))
For col = LBound(originalArray, 2) To UBound(originalArray, 2)
arrayOfColumnToReturn(col) = col
Next col
End If
' If the caller don't pass an array for partial match check if it pass the spacial value 1, if true the partial macth will be performed on values in columns to return
If Not IsArray(partialMatchColumnsArray) Then
If partialMatchColumnsArray = 1 Then partialMatchColumnsArray = arrayOfColumnToReturn
End If
ReDim tempFilteredArray(firstColumn To lastColumn, firstRow To firstRow) As Variant
filteredArrayRow = firstRow - 1
For row = firstRow To lastRow
' Start Exact Match check
If firstExactMatchColumn > -1 Then
If LCase(originalArray(row, firstExactMatchColumn)) <> LCase(firstExactMatchValue) Then GoTo SkipRow
End If
If secondExactMatchColumn > -1 Then
If LCase(originalArray(row, secondExactMatchColumn)) <> LCase(secondExactMatchValue) Then GoTo SkipRow
End If
If thirdExactMatchColumn > -1 Then
If LCase(originalArray(row, thirdExactMatchColumn)) <> LCase(thirdExactMatchValue) Then GoTo SkipRow
End If
' End Exact Match check
' Start Negative Match check
If firstColumnToExclude > -1 Then
If LCase(originalArray(row, firstColumnToExclude)) = LCase(firstValueToExclude) Then GoTo SkipRow
End If
If secondColumnToExclude > -1 Then
If LCase(originalArray(row, secondColumnToExclude)) = LCase(secondValueToExclude) Then GoTo SkipRow
End If
If thirdColumnToExclude > -1 Then
If LCase(originalArray(row, thirdColumnToExclude)) = LCase(thirdValueToExclude) Then GoTo SkipRow
End If
' End Negative Match check
' Start isBetween check
If firstColumnIsBetween > -1 Then
If originalArray(row, firstColumnIsBetween) < firstLowValue Or originalArray(row, firstColumnIsBetween) > firstHighValue Then GoTo SkipRow
End If
If secondColumnIsBetween > -1 Then
If originalArray(row, secondColumnIsBetween) < secondLowValue Or originalArray(row, secondColumnIsBetween) > secondHighValue Then GoTo SkipRow
End If
If thirdColumnIsBetween > -1 Then
If originalArray(row, thirdColumnIsBetween) < thirdLowValue Or originalArray(row, thirdColumnIsBetween) < thirdHighValue Then GoTo SkipRow
End If
' End isBetween check
' Start partial match check
If IsArray(partialMatchColumnsArray) Then
For partialCol = LBound(partialMatchColumnsArray) To UBound(partialMatchColumnsArray)
If InStr(1, originalArray(row, partialMatchColumnsArray(partialCol)), partialMatchValue, vbTextCompare) > 0 Then
GoTo WriteRow
End If
Next partialCol
GoTo SkipRow
End If
' End partial match check
WriteRow:
' Writing data in the filtered array
filteredArrayRow = filteredArrayRow + 1
ReDim Preserve tempFilteredArray(firstColumn To lastColumn, firstRow To filteredArrayRow) As Variant
For col = firstColumn To lastColumn
tempFilteredArray(col, filteredArrayRow) = originalArray(row, arrayOfColumnToReturn(col))
Next col
SkipRow:
Next row
If filteredArrayRow > firstRow - 1 Then
FilterArray = Application.Transpose(tempFilteredArray)
End If
Erase originalArray
Erase arrayOfColumnToReturn
If IsArray(partialMatchColumnsArray) Then Erase partialMatchColumnsArray
If IsArray(tempFilteredArray) Then Erase tempFilteredArray
End Function