UDF for Counting Unique Text Within Date Range

robert41

New Member
Joined
Oct 9, 2012
Messages
6
Hi all, I have this wonderful User Defined Function below that counts unique text within a range. The problem is you cant specify a date range as as in COUNTIFS functions. Can this code be modified to specify date ranges? For example
Code:
=CountUnique(Date_rng,">=01/09/2012",Date_rng,"<=30/09/2012")
Here's the code:

Code:
Public Function CountUnique(rng As Variant) As Variant

Dim Test As New Collection
Dim Value As Variant

rng = rng.Value

On Error Resume Next
For Each Value In rng

If Len(Value) > 0 Then Test.Add Value, CStr(Value)

Next Value
On Error GoTo 0

CountUnique = Test.Count

End Function
 

Excel Facts

Get help while writing formula
Click the italics "fx" icon to the left of the formula bar to open the Functions Arguments dialog. Help is displayed for each argument.
Hi,
Try this:
Rich (BB code):
' ZVI:2012-11-06 http://www.mrexcel.com/forum/excel-questions/667989-udf-counting-unique-text-within-date-range.html
' Count unique values with optional min/max boundaries
' Arguments:
'   Where - Range or Array
'   MinValue - optional minimum value to be count
'   MaxValue - optional maximum value to be count
Function CountUnique(Where, Optional MinValue, Optional MaxValue) As Long
  Dim a, i As Long, x
  a = Where
  If Not IsArray(a) Then ReDim a(1): a(1) = Where
  If Not IsMissing(MinValue) Then i = i + 1
  If Not IsMissing(MaxValue) Then i = i + 2
  On Error Resume Next
  With New Collection
    For Each x In a
      If VarType(x) <> vbError Then
        If Len(x) > 0 Then
          If i = 0 Then
             .Add vbNullString, CStr(x)
          ElseIf i = 1 Then
            If x >= MinValue Then .Add vbNullString, CStr(x)
          ElseIf i = 2 Then
            If x <= MaxValue Then .Add vbNullString, CStr(x)
          Else
            If x >= MinValue And x <= MaxValue Then .Add vbNullString, CStr(x)
          End If
        End If
      End If
    Next
    CountUnique = .Count
  End With
  Err.Clear
End Function
Regards
 
Last edited:
Upvote 0
Usage:

1. Count unique values:
=CountUnique(A1:A100)

2. Count unique values with condition: >= 01-Sep-2012
=CountUnique(A1:A100,DATE(2012,09,1))

3. Count unique values with condition: <= 08-Nov-2012
=CountUnique(A1:A100, ,DATE(2012,11,8))

4. Count unique values with conditions: >= 01-Sep-2012 And <= 08-Nov-2012
=CountUnique(A1:A100,DATE(2012,09,1),DATE(2012,11,8))

Boundaries can be any type (but not errors) values or cell references.
 
Last edited:
Upvote 0
Thanks ZVI your solution is what I need but the results are not quite right. I am not sure if its due to the date formating or the code but here's a sample of my worksheet, my implementation and results below:

[TABLE="width: 264"]
<tbody>[TR]
[TD][/TD]
[TD]A[/TD]
[TD]B[/TD]
[/TR]
[TR]
[TD]1[/TD]
[TD]Taneisha Hanson[/TD]
[TD="align: right"]14-Mar-12[/TD]
[/TR]
[TR]
[TD]2[/TD]
[TD]Barbara Lewis[/TD]
[TD="align: right"]30-Mar-12[/TD]
[/TR]
[TR]
[TD]3[/TD]
[TD]Kevin Morgan[/TD]
[TD="align: right"]29-Mar-12[/TD]
[/TR]
[TR]
[TD]4[/TD]
[TD]Kern Facey[/TD]
[TD="align: right"]16-Oct-12[/TD]
[/TR]
[TR]
[TD]5[/TD]
[TD]Kern Facey[/TD]
[TD="align: right"]29-Oct-12[/TD]
[/TR]
[TR]
[TD]6[/TD]
[TD]Kadine Foster[/TD]
[TD="align: right"]01-Sep-12[/TD]
[/TR]
[TR]
[TD]7[/TD]
[TD]Barbara Lewis[/TD]
[TD="align: right"]24-Sep-12[/TD]
[/TR]
[TR]
[TD]8[/TD]
[TD]Chris Free[/TD]
[TD="align: right"]01-Oct-12[/TD]
[/TR]
[TR]
[TD]9[/TD]
[TD]Telvor Foster[/TD]
[TD="align: right"]01-Mar-12[/TD]
[/TR]
</tbody>[/TABLE]

1. Count unique values with no conditions:
=CountUnique(A1:A9)
Actual Result:7, Desired result:7

2. Count unique values with condition: >= 01-Sep-2012:
=CountUnique(A1:A9,DATE(2012,9,1))
Actual Result:7, Desired result:4

3. Count unique values with condition: <= 31-Mar-2012:
=CountUnique(A1:A9, ,DATE(2012,3,31))
Actual Result:0, Desired Result:4

4. Count unique values with conditions: >= 01-Sep-2012 And <= 01-Oct-2012:
=CountUnique(A1:A9,DATE(2012,9,1),DATE(2012,10,1))
Actual Results:0, Desired Result:3

Thanks again and kind regards
 
Upvote 0
Hi all, I have this wonderful User Defined Function below that counts unique text within a range. The problem is you cant specify a date range as as in COUNTIFS functions. Can this code be modified to specify date ranges? For example
Code:
=CountUnique(Date_rng,">=01/09/2012",Date_rng,"<=30/09/2012")
Doesn't your initial post was about single range Date_rng ? ;)

Ok, here is the version for the post #4 case with separate ranges for data and for conditional values.

*ABCD
Taneisha Hanson
Barbara Lewis
Kevin Morgan
Kern Facey
Kern Facey
Kadine Foster
Barbara Lewis
Chris Free
Telvor Foster

<tbody>
[TD="bgcolor: #cacaca, align: center"]1[/TD]

[TD="align: right"]14-Mar-12[/TD]

[TD="align: center"]UniqueCount[/TD]

[TD="bgcolor: #cacaca, align: center"]2[/TD]

[TD="align: right"]30-Mar-12[/TD]

[TD="align: center"]7[/TD]

[TD="bgcolor: #cacaca, align: center"]3[/TD]

[TD="align: right"]29-Mar-12[/TD]

[TD="align: center"]4[/TD]

[TD="bgcolor: #cacaca, align: center"]4[/TD]

[TD="align: right"]16-Oct-12[/TD]

[TD="align: center"]4[/TD]

[TD="bgcolor: #cacaca, align: center"]5[/TD]

[TD="align: right"]29-Oct-12[/TD]

[TD="align: center"]3[/TD]

[TD="bgcolor: #cacaca, align: center"]6[/TD]

[TD="align: right"]1-Sep-12[/TD]

[TD="bgcolor: #cacaca, align: center"]7[/TD]

[TD="align: right"]24-Sep-12[/TD]

[TD="bgcolor: #cacaca, align: center"]8[/TD]

[TD="align: right"]1-Oct-12[/TD]

[TD="bgcolor: #cacaca, align: center"]9[/TD]

[TD="align: right"]1-Mar-12[/TD]

</tbody>

Spreadsheet Formulas
CellFormula
D2=CountUnique(A1:A9)
D3=CountUnique(A1:A9,B1:B9,DATE(2012,9,1))
D4=CountUnique(A1:A9,B1:B9, ,DATE(2012,3,31))
D5=CountUnique(A1:A9,B1:B9,DATE(2012,9,1),DATE(2012,10,1))

<tbody>
</tbody>

<tbody>
</tbody>


Excel tables to the web >> Excel Jeanie HTML 4

The code of UDF:

Rich (BB code):
' ZVI:2012-11-07 http://www.mrexcel.com/forum/excel-questions/667989-udf-counting-unique-text-within-date-range.html
' Count unique values with optional min/max boundaries.
' Separate ranges for data value and condition values are supported.
' Arguments:
'    Data     - required, Range with data values which unique count is returned
'    Cond     - optional, Range with values for conditions MinValue or/and MaxValue
'    MinValue - optional, minimum value in Cond range to allow counting
'    MaxValue - optional, maximum value in Cond range to allow counting
' Examples:
' 1) Unique count of A1:A9 without conditions
'    =CountUnique( A1:A9 )
' 2) Unique count of A1:A9 with B1:B9 >= DATE(2012,9,1)
'    =CountUnique( A1:A9, B1:B9, DATE(2012,9,1) )
' 3) Unique count of A1:A9 with B1:B9 <= DATE(2012,3,31)
'    =CountUnique( A1:A9, B1:B9, , DATE(2012,3,31) )
' 4) Unique count of A1:A9 with B1:B9 >= DATE(2012,9,1) And B1:B9 <= DATE(2012,10,1)
'    =CountUnique( A1:A9, B1:B9, DATE(2012,9,1), DATE(2012,10,1) )
Function CountUnique(Data As Range, Optional Cond As Range, Optional MinValue, Optional MaxValue) As Long
 
  Dim a, b, v
  Dim c As Long, cs As Long, e As Long, i As Long, r As Long, rs As Long
  Dim IsCond As Boolean
  Dim k As String
 
  ' Copy Data and Cond values to the arrays
  a = Data.Value
  rs = UBound(a, 1)
  cs = UBound(a, 2)
  If Not IsArray(a) Then ReDim a(1 To 1, 1 To 1): a(1, 1) = Data.Value
  If Not Cond Is Nothing Then IsCond = Data.Address <> Cond.Address
  If IsCond Then
    b = Cond.Value
    If Not IsArray(b) Then ReDim b(1 To 1, 1 To 1): b(1, 1) = Cond.Value
    If UBound(b, 1) <> rs Or UBound(b, 2) <> cs Then CountUnique = "#Size!": Exit Function
  End If
 
  ' Configure conditions index
  If Not IsMissing(MinValue) Then i = i + 1
  If Not IsMissing(MaxValue) Then i = i + 2
 
  ' Save error number if it was before calling this function
  e = Err.Number
 
  ' Suppress stop on error
  On Error Resume Next
 
  ' Count unique values with/without conditions
  With New Collection
    For r = 1 To rs
      For c = 1 To cs
        k = vbNullString
        k = Trim(a(r, c))
        If Len(k) Then
          If IsCond Then v = b(r, c) Else v = a(r, c)
          If i = 0 Then
            .Add vbNullString, k
          ElseIf i = 1 Then
            If v >= MinValue Then .Add vbNullString, k
          ElseIf i = 2 Then
            If v <= MaxValue Then .Add vbNullString, k
          Else
            If v >= MinValue And v <= MaxValue Then .Add vbNullString, k
          End If
        End If
      Next
    Next
    CountUnique = .Count
  End With
 
  ' Restore previous error number
  Err.Number = e
 
End Function

Regards,
 
Upvote 0
This updated version supports also VBA 1D or 2D arrays.

Rich (BB code):
' ZVI:2012-11-07 - http://www.mrexcel.com/forum/excel-questions/667989-udf-counting-unique-text-within-date-range.html
' Count unique values in Data with optional min/max boundaries MinValue, MaxValue in Cond.
' Arguments:
'    Data     - required, Range or Array with data values which unique count is returned
'    Cond     - optional, Range or Array with values for conditions MinValue or/and MaxValue
'    MinValue - optional, minimum value in Cond range to allow counting
'    MaxValue - optional, maximum value in Cond range to allow counting
' Examples:
' 1) UDF, count unique of A1:A9 without conditions
'    =CountUnique( A1:A9 )
' 2) UDF, count unique of A1:A9 with B1:B9 >= DATE(2012,9,1)
'    =CountUnique( A1:A9, B1:B9, DATE(2012,9,1) )
' 3) UDF, count unique of A1:A9 with B1:B9 <= DATE(2012,3,31)
'    =CountUnique( A1:A9, B1:B9, , DATE(2012,3,31) )
' 4) UDF, count unique A1:A9 with B1:B9 >= DATE(2012,9,1) And B1:B9 <= DATE(2012,10,1)
'    =CountUnique( A1:A9, B1:B9, DATE(2012,9,1), DATE(2012,10,1) )
' 5) VBA, count unique of a() with b() >= DATE(2012,9,1) And b() <= DATE(2012,10,1)
'    n = CountUnique(a(), b(), DateSerial(2012, 9, 1), DateSerial(2012, 10, 1))
'    Note: VBA arrays can be 1 or 2 dimensions but with the same LBounds and Ubounds
Function CountUnique(Data, Optional Cond, Optional MinValue, Optional MaxValue)
 
  Dim a, b, v
  Dim c As Long, e As Long, i As Long, r As Long
  Dim LBa1 As Long, LBa2 As Long, UBa1 As Long, UBa2 As Long
  Dim LBb1 As Long, LBb2 As Long, UBb1 As Long, UBb2 As Long
  Dim Is1D As Boolean, Ok As Boolean
  Dim k As String
 
  ' Save error number for the case it was present before calling this function
  e = Err.Number
 
  ' Suppress stop on error
  On Error Resume Next
 
  ' Configure conditional index
  If Not IsMissing(MinValue) Then i = i + 1
  If Not IsMissing(MaxValue) Then i = i + 2
 
  ' Copy Data values to a() array
  a = Data
  If Not IsArray(a) Then ReDim a(1 To 1, 1 To 1): a(1, 1) = Data
  LBa1 = LBound(a, 1)
  UBa1 = UBound(a, 1)
  LBa2 = LBound(a, 2)
  If Err = 0 Then UBa2 = UBound(a, 2) Else LBa2 = 1: UBa2 = 1: Is1D = True: Err.Clear
 
  ' Copy Cond values to b() array
  If i > 0 Then
    b = Cond
    If Not IsArray(b) Then ReDim b(1 To 1, 1 To 1): b(1, 1) = Cond
    LBb1 = LBound(b, 1)
    UBb1 = UBound(b, 1)
    LBb2 = LBound(b, 2)
    If Err = 0 Then UBb2 = UBound(b, 2) Else LBb2 = 1: UBb2 = 1: Is1D = True: Err.Clear
    ' Compare dimentions of arrays
    If LBa1 <> LBb1 Or UBa1 <> UBb1 Or LBa2 <> LBb2 Or UBa2 <> UBb2 Then CountUnique = "#Size!": Exit Function
  End If
 
  ' Count unique values with/without conditions
  With New Collection
    For r = LBa1 To UBa1
      For c = LBa2 To UBa2
        k = vbNullString
        If Is1D Then k = Trim(a(r)) Else k = Trim(a(r, c))
        If Len(k) Then
          Ok = False
          If i = 0 Then
            Ok = True
          ElseIf i = 1 Then
            If Is1D Then Ok = b(r) >= MinValue Else Ok = b(r, c) >= MinValue
          ElseIf i = 2 Then
            If Is1D Then Ok = b(r) <= MaxValue Else Ok = b(r, c) <= MaxValue
          Else
            If Is1D Then
              Ok = b(r) >= MinValue And b(r) <= MaxValue
            Else
              Ok = b(r, c) >= MinValue And b(r, c) <= MaxValue
            End If
          End If
          If Ok Then .Add vbNullString, k
        End If
      Next
    Next
    CountUnique = .Count
  End With
 
  ' Restore saved error number
  Err.Number = e
 
End Function
 
 
' Test VBA 1D-array processing
Sub Test5()
  Dim a(), b()
  ' Copy A1:A9 to 1D-array
  a() = WorksheetFunction.Transpose(Range("A1:A9"))
  ' To prevent date to string converting don't use Range("B1:B9").Value at transposing!
  ' Use just Range("B1:B9") without .Value
  b() = WorksheetFunction.Transpose(Range("B1:B9"))
  ' Show result
  Debug.Print CountUnique(a(), b(), DateSerial(2012, 9, 1), DateSerial(2012, 10, 1))
End Sub
 
Last edited:
Upvote 0
Surely this could be done with an array formula?
Yes sure, may be an array formula is too simple to be interesting :lol:
At least VBA solution was requested.

Ok, here is example of array formula for count uniques in A1:A9 with B1:B9 >= DATE(2012,9,1) And B1:B9 <= DATE(2012,10,1) :

=SUM(IF(FREQUENCY(IF(B1:B9>=DATE(2012,9,1),IF(B1:B9<=DATE(2012,10,1),MATCH("~"&A1:A9,A1:A9&"",0))),ROW(A1:A9)-ROW(A1)+1),1))

Ctrl-Shift-Enter is required for entering this formula.
 
Upvote 0
Vladimir many thanks! Your UDF now works and I can stop pulling my hair out after trying 4 weeks to solve this problem! I haven't tried your VBA version yet but thanks for going the extra mile with this...it is much appreciated. And yes Blade Hunter an array formula could work but I have literally hundreds of rows of records and excel and/or my PC always seem to "choke" when using array formulas with that many records. But maybe it was the type of array formula I was using so I will try both this UDF and the array formula above to see which works the best. Many thanks again and kind regards. I will mark this post as solved
 
Upvote 0

Forum statistics

Threads
1,223,723
Messages
6,174,113
Members
452,544
Latest member
aush

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top