VBA Countifsfunction – 标准的可变数量

如果我想在一个函数中使用countifs,有时候它只需要2个critera,有时候只需要3个

什么是最好的方式,我可以做到这一点,而不使用2个function,2和3标准。

Function Check(sh as worksheet, col1 as range, crit1 as range,col2 as range, crit2 as range,col3 as range, crit3 as range) If Application.CountIfs(col1,crit1,col2,crit2,col3,crit3) > 1 Then 'true End If End Function 

这只是一个例子来说明这个问题

我不清楚为什么当COUNTIFS直接接受可变数量的参数¹时,为什么一个基于COUNTFS函数的UDF需要一个不规则长度的参数参数对于一个UDF是必要的,但是我确信它是一个总体规划的一部分。

 Function how_many_do_you_want_to_count_to(ParamArray rCOUNTs() As Variant) Dim v As Long, sFormula As String sFormula = "=COUNTIFS(" For v = LBound(rCOUNTs) To UBound(rCOUNTs) Step 2 sFormula = sFormula & rCOUNTs(v).Address(0, 0, external:=True) & Chr(44) _ & rCOUNTs(v + 1).Address(0, 0, external:=True) _ & IIf(v < UBound(rCOUNTs) - 1, Chr(44), Chr(41)) Next v how_many_do_you_want_to_count_to = Application.Evaluate(sFormula) End Function 

¹ 在COUNTIFS中最多允许127个范围/条件对

你可以咬牙切齿,让Application.WorkSheetFunction.CountIfs对程序员更友好,并允许程序员传入一个数组,而不需要显式的input参数。 那么你可以在你的Check函数中使用这个版本。 下面的代码是(大部分)由另一个VBA子,我不包括:

 Function VBA_CountIfs(args As Variant) As Double Dim n As Long n = UBound(args) 'assumed to be 0-based With Application.WorksheetFunction Select Case n: Case 1: VBA_CountIfs = .CountIfs(args(0), args(1)) Case 3: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3)) Case 5: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5)) Case 7: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7)) Case 9: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9)) Case 11: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11)) Case 13: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13)) Case 15: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15)) Case 17: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17)) Case 19: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19)) Case 21: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20), args(21)) Case 23: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20), args(21), args(22), args(23)) Case 25: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20), args(21), args(22), args(23), args(24), args(25)) Case 27: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20), args(21), args(22), args(23), args(24), args(25), args(26), args(27)) Case 29: VBA_CountIfs = .CountIfs(args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7), args(8), args(9), args(10), args(11), args(12), args(13), args(14), args(15), args(16), args(17), args(18), args(19), args(20), args(21), args(22), args(23), args(24), args(25), args(26), args(27), args(28), args(29)) Case Else: VBA_CountIfs = -1 'error flag End Select End With End Function 

举例说明如何使用它:

 Sub test() Debug.Print VBA_CountIfs(Array(Range("A1:A5"), Range("B1"), Range("C1:C5"), Range("D1"))) End Sub 

(这将返回我的testing表正确的结果)。 如果你发现一个很好的string表示范围,你可以使用Split函数创buildVBA_CountIfs的input。

这个想法的一个变种是将声明VBA_CountIfs的input为ParamArray

 Function Check(sh as worksheet, col1 as range, crit1 as range, _ col2 as range, crit2 as range, _ Optional col3 as range, Optional crit3 as range) Dim n If IsMissing(col3) Then n = Application.CountIfs(col1,crit1,col2,crit2) else n = Application.CountIfs(col1,crit1,col2,crit2,col3,crit3) end if If n > 1 Then 'true End If End Function 

或者类似于@ JohnColeman的方法:

 Public Function Check(sh As Worksheet, ParamArray args()) Dim rv, f, n, num f = "COUNTIFS(" For n = 0 To UBound(args) Step 2 f = f & IIf(n > 0, ",", "") & args(n).Address(False, False) & "," Select Case TypeName(args(n + 1)) Case "Range": f = f & args(n + 1).Address(False, False) Case "Integer", "Long", "Double": f = f & args(n + 1) Case "String": f = f & """" & args(n + 1) & """" End Select Next n num = args(0).Parent.Evaluate(f & ")") If num > 1 Then 'etc etc End If End Function