Public Function ConcatenateIf(ByVal rngCriteriaRange As Excel.Range, _
ByVal varCriteria As Variant, _
ByVal rngValues As Excel.Range, _
Optional ByVal strDelimiter As String = " ") As Variant
Dim lngRows As Long, lngCols As Long
Dim blnErr As Boolean, lngErr As XlCVError
Dim strCritAddress As String
Dim strValAddress As String
Dim varOperators As Variant: varOperators = VBA.Array("=", "<>", ">", "<", ">=", "<=")
Dim strOperator As String
Dim varResults As Variant
With rngCriteriaRange
lngRows = .Rows.Count
lngCols = .Columns.Count
End With
'#REF! if 2D criteria range is passed
blnErr = CBool(lngRows > 1 And lngCols > 1)
If blnErr Then
lngErr = xlErrRef
GoTo err_exit
End If
'#VALUE! if values range dimension is not the same size and orientation as criteria range
With rngValues
blnErr = CBool(lngRows <> .Rows.Count)
blnErr = CBool(blnErr Or lngCols <> .Columns.Count)
If blnErr Then
lngErr = xlErrValue
GoTo err_exit
End If
End With
'#N/A if the criteria is an array (or more than one cell)
blnErr = IsArray(varCriteria)
If blnErr Then
lngErr = xlErrNA
GoTo err_exit
End If
'Split the operator from the criteria, if an operator has been included
strOperator = Left$(varCriteria, 2)
If IsNumeric(Application.Match(strOperator, varOperators, 0)) Then
varCriteria = Mid$(varCriteria, 3)
Else
strOperator = Left$(varCriteria, 1)
If IsNumeric(Application.Match(strOperator, varOperators, 0)) Then
varCriteria = Mid$(varCriteria, 2)
Else
strOperator = "="
End If
End If
'Make sure the criteria type is correct, and concatenate the operator with the criteria
If IsDate(varCriteria) Then
varCriteria = strOperator & CDbl(varCriteria)
Else
If IsNumeric(varCriteria) Then
varCriteria = strOperator & varCriteria
Else
varCriteria = strOperator & Chr$(34) & varCriteria & Chr$(34)
End If
End If
'Get the addresses of the criteria and values ranges
strCritAddress = rngCriteriaRange.Address(external:=True)
strValAddress = rngValues.Address(external:=True)
'Construct an array of the results
If lngRows > 1 Then
varResults = Evaluate("transpose(if(" & strCritAddress & varCriteria & "," & strValAddress & "))")
Else
varResults = Evaluate("if(" & strCritAddress & varCriteria & "," & strValAddress & ")")
End If
'Remove non-matching items from the array, and concatenate the remaining items
varResults = Filter(varResults, False, False)
ConcatenateIf = Join$(varResults, strDelimiter)
Exit Function
err_exit:
ConcatenateIf = CVErr(lngErr)
End Function