A nice, flexible and fast way to do this is with code like this.
This presumes your list is in column A starting in A1. This needs a
reference to the free file:
dhRichClient, written by Olaf Schmidt and which can be downloaded from:
www.datenhaus.de/Downloads/dhRichClientDemo.zip
It may look complex and a lot of code, but it is fast and you don't have to
understand it.
Function MakeFrequencyArray(arrVariant As Variant, _
Optional lCols As Long = -1, _
Optional bSortDescOnCount As Boolean = True, _
Optional bSortAscOnCount As Boolean, _
Optional bSortDescOnItem As Boolean, _
Optional bSortAscOnItem As Boolean, _
Optional strFormat As String) As Variant
Dim i As Long
Dim c As Long
Dim LB As Long
Dim UB As Long
Dim LB2 As Long
Dim UB2 As Long
Dim cSD1 As cSortedDictionary
Dim cSD2 As cSortedDictionary
Dim lCount As Long
Dim lcSD1Count As Long
Dim lcSD2Count As Long
Dim arrReturn
LB = LBound(arrVariant)
UB = UBound(arrVariant)
Set cSD1 = New cSortedDictionary
If lCols = -1 Then
For i = LB To UB
If cSD1.Exists(arrVariant(i)) Then
lCount = cSD1.Item(arrVariant(i))
lCount = lCount + 1
cSD1.Item(arrVariant(i)) = lCount
Else
cSD1.Add arrVariant(i), 1
End If
Next i
Else
LB2 = LBound(arrVariant, 2)
UB2 = UBound(arrVariant, 2)
If lCols = 1 Then 'to gain some speed?
For i = LB To UB
If cSD1.Exists(arrVariant(i, LB2)) Then
lCount = cSD1.Item(arrVariant(i, LB2))
lCount = lCount + 1
cSD1.Item(arrVariant(i, LB2)) = lCount
Else
cSD1.Add arrVariant(i, LB2), 1
End If
Next i
Else
For i = LB To UB
For c = LB2 To UB2
If cSD1.Exists(arrVariant(i, c)) Then
lCount = cSD1.Item(arrVariant(i, c))
lCount = lCount + 1
cSD1.Item(arrVariant(i, c)) = lCount
Else
cSD1.Add arrVariant(i, c), 1
End If
Next c
Next i
End If
End If
If bSortDescOnCount Or bSortAscOnCount Then
Set cSD2 = New cSortedDictionary
cSD2.UniqueKeys = False
For i = 1 To cSD1.Count
cSD2.Add cSD1.ItemByIndex(i - 1), cSD1.KeyByIndex(i - 1)
Next i
lcSD2Count = cSD2.Count
'return a 1-based 2-D variant array
'----------------------------------
ReDim arrReturn(1 To lcSD2Count, 1 To 4)
If Len(strFormat) > 0 Then
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = lcSD2Count - i
arrReturn(lcSD2Count - i, 2) = Format(cSD2.ItemByIndex(i),
strFormat)
'for some reason this is needed to avoid a currency sign in front
of the number
'------------------------------------------------------------------------------
arrReturn(lcSD2Count - i, 3) = CLng(cSD2.KeyByIndex(i))
arrReturn(lcSD2Count - i, 4) = _
Format(arrReturn(lcSD2Count - i, 3) / (UB + (1 - LB)), "0.00%")
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = i + 1
arrReturn(i + 1, 2) = Format(cSD2.ItemByIndex(i), strFormat)
arrReturn(i + 1, 3) = CLng(cSD2.KeyByIndex(i))
arrReturn(i + 1, 4) = _
Format(arrReturn(i + 1, 3) / (UB + (1 - LB)), "0.00%")
Next i
End If
Else
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = lcSD2Count - i
arrReturn(lcSD2Count - i, 2) = cSD2.ItemByIndex(i)
arrReturn(lcSD2Count - i, 3) = CLng(cSD2.KeyByIndex(i))
arrReturn(lcSD2Count - i, 4) = _
Format(arrReturn(lcSD2Count - i, 3) / (UB + (1 - LB)), "0.00%")
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = i + 1
arrReturn(i + 1, 2) = cSD2.ItemByIndex(i)
arrReturn(i + 1, 3) = CLng(cSD2.KeyByIndex(i))
arrReturn(i + 1, 4) = _
Format(arrReturn(i + 1, 3) / (UB + (1 - LB)), "0.00%")
Next i
End If
End If
Else 'If bSortDescOnCount Or bSortAscOnCount
lcSD1Count = cSD1.Count
'return a 1-based 2-D variant array
'----------------------------------
ReDim arrReturn(1 To lcSD1Count, 1 To 4)
If Len(strFormat) > 0 Then
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = lcSD1Count - i
arrReturn(lcSD1Count - i, 2) = Format(cSD1.KeyByIndex(i),
strFormat)
arrReturn(lcSD1Count - i, 3) = CLng(cSD1.ItemByIndex(i))
arrReturn(lcSD2Count - i, 4) = _
Format(arrReturn(lcSD1Count - i, 3) / (UB + (1 - LB)), "0.00%")
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = i + 1
arrReturn(i + 1, 2) = Format(cSD1.KeyByIndex(i), strFormat)
arrReturn(i + 1, 3) = CLng(cSD1.ItemByIndex(i))
arrReturn(i + 1, 4) = _
Format(arrReturn(i + 1, 3) / (UB + (1 - LB)), "0.00%")
Next i
End If
Else
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = lcSD1Count - i
arrReturn(lcSD1Count - i, 2) = cSD1.KeyByIndex(i)
arrReturn(lcSD1Count - i, 3) = CLng(cSD1.ItemByIndex(i))
arrReturn(lcSD2Count - i, 4) = _
Format(arrReturn(lcSD1Count - i, 3) / (UB + (1 - LB)), "0.00%")
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = i + 1
arrReturn(i + 1, 2) = cSD1.KeyByIndex(i)
arrReturn(i + 1, 3) = CLng(cSD1.ItemByIndex(i))
arrReturn(i + 1, 4) = _
Format(arrReturn(i + 1, 3) / (UB + (1 - LB)), "0.00%")
Next i
End If
End If
End If 'If bSortDescOnCount Or bSortAscOnCount
MakeFrequencyArray = arrReturn
End Function
Sub test()
Dim arr
Dim arrResult
arr = Range(Cells(1), Cells(15, 1))
arrResult = MakeFrequencyArray(arr, 1)
Range(Cells(3), Cells(UBound(arrResult), UBound(arrResult, 2) + 2)) =
arrResult
End Sub
RBS
Hello Everyone,
I looking for the way to get top 5 most reccurent values in range/
column and sort it descending.
For example, I've got values:
apple
dog
dog
pig
apple
flower
sweet
door
apple
apple
pink
drink
door
swim
drink
What I would like to do is get top 5:
1. Apple - 4 times
2. dog - 2 times
3. door - 2 times
4. drink - 2 times
5. flower - 1 time
If you have any ideas please let mi know.
Best regards,
Bartosz D³ugokêcki