ExcelBanter

ExcelBanter (https://www.excelbanter.com/)
-   Excel Programming (https://www.excelbanter.com/excel-programming/)
-   -   Top 5 most recurrent values in range. (https://www.excelbanter.com/excel-programming/420625-top-5-most-recurrent-values-range.html)

bentor

Top 5 most recurrent values in range.
 
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

[email protected]

Top 5 most recurrent values in range.
 
Hi
If your data is in A2 to A16, in cell B2 type

= countif($A$2:$A$16,A2)

Fill this formula down. This will count the occurance of each item in
your list. Now sort using column B.
regards
Paul

On Nov 28, 10:07*am, bentor wrote:
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



bentor

Top 5 most recurrent values in range.
 
On 28 Lis, 12:53, wrote:
Hi
If your data is in A2 to A16, in cell B2 type

= countif($A$2:$A$16,A2)

Fill this formula down. This will count the occurance of each item in
your list. Now sort using column B.
regards
Paul

On Nov 28, 10:07Â*am, bentor wrote:



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- Ukryj cytowany tekst -


- PokaĹĽ cytowany tekst -


In that way, you will get something like that:
apple - 4
apple - 4
apple - 4
apple - 4
dog - 2
dog - 2
door - 2
door - 2
drink - 2
drink - 2
flower - 1

Regards,
Bartosz Długokęcki

JP[_4_]

Top 5 most recurrent values in range.
 
How about a PivotTable? You can limit it to the top 5 values and sort
descending. Drop the column header into the data field to get a count
of unique items.

--JP

On Nov 28, 5:07*am, bentor wrote:
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



RB Smissaert

Top 5 most recurrent values in range.
 
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



"bentor" wrote in message
...
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


RB Smissaert

Top 5 most recurrent values in range.
 
If you don't need the rank and percentage in the output then you could leave
those lines out and do:

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 2)

If Len(strFormat) 0 Then
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = Format(cSD2.ItemByIndex(i),
strFormat)
'for some reason this is needed to avoid a currency sign in front
of the number
'------------------------------------------------------------------------------
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = Format(cSD2.ItemByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
Next i
End If
Else
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = cSD2.ItemByIndex(i)
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = cSD2.ItemByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
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 2)

If Len(strFormat) 0 Then
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = Format(cSD1.KeyByIndex(i),
strFormat)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = Format(cSD1.KeyByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
Else
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = cSD1.KeyByIndex(i)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = cSD1.KeyByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
End If

End If 'If bSortDescOnCount Or bSortAscOnCount

MakeFrequencyArray = arrReturn

End Function


RBS


"RB Smissaert" wrote in message
...
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



"bentor" wrote in message
...
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



AndrewCerritos

Top 5 most recurrent values in range.
 
Here is my take on this. Briefly:
(1) the values is string type, in column A of worksheet "top5"
(2) the range is known (otherwise have to check the last row containing value)
(3) if you need to keep the original data and order, copy the value into
"top5" worksheet.
(4) I am using the Sort object
(5) Obviously, the routine can be further optimized

Private Sub GetTop5()
Dim rngSource As Range ' the source range to work with
Dim celX As Range ' looping cell variable
Dim strLast As String ' remember last value string: for counting
Dim iLastRow As Long ' remember last row: for counting

Worksheets("top5").Activate ' the worksheet to work on
Set rngSource = ActiveSheet.[A1:B15] ' the range to work with

' 1) Sort on Column A
With ActiveWorkbook.ActiveSheet.Sort
.SortFields.Clear ' clear the sorting fields
.SortFields.Add Key:=Range("A1"), Order:=xlAscending
.SetRange rngSource ' the range to sort on
.Header = xlNo ' NO: we don't have headers
.MatchCase = False ' NOT case-sensitive
.Orientation = xlTopToBottom ' sort by row
.SortMethod = xlPinYin ' based on sound (not strokes)
.Apply ' do the soring
End With

' 2) Count frequency
' -- the duplicated ones will get count 0, so
' when sort on the count, they will appear at the end
strLast = "" ' start with impossible value
iLastRow = 0 ' start with non-existing row
For Each celX In Intersect(rngSource, Range("A:A")) ' loop through
column A
If celX.Value = strLast Then
Cells(iLastRow, 2).Value = Cells(iLastRow, 2).Value + 1
celX.Offset(0, 1) = 0 ' the duplicate row will count as 0
Else
celX.Offset(0, 1) = 1 ' the first row of unique value
iLastRow = celX.Row ' remember this as the last row
strLast = celX.Value ' remember this as the last value
End If
Next celX

' 3) Sort on Frequency, then Value
'
With ActiveWorkbook.ActiveSheet.Sort
.SortFields.Clear ' clear the sorting fields
.SortFields.Add Key:=Range("B1"), Order:=xlDescending
.SortFields.Add Key:=Range("A1"), Order:=xlAscending
.SetRange rngSource ' the range to sort on
.Header = xlNo ' NO: we don't have headers
.MatchCase = False ' NOT case-sensitive
.Orientation = xlTopToBottom ' sort by row
.SortMethod = xlPinYin ' based on sound (not strokes)
.Apply ' sort it
End With

' The results will be listed in the order of
' a) the frequency (column B) in descending order
' b) for the same frequency: the value (column A) in ascending order
End Sub


"RB Smissaert" wrote:

If you don't need the rank and percentage in the output then you could leave
those lines out and do:

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 2)

If Len(strFormat) 0 Then
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = Format(cSD2.ItemByIndex(i),
strFormat)
'for some reason this is needed to avoid a currency sign in front
of the number
'------------------------------------------------------------------------------
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = Format(cSD2.ItemByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
Next i
End If
Else
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = cSD2.ItemByIndex(i)
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = cSD2.ItemByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
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 2)

If Len(strFormat) 0 Then
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = Format(cSD1.KeyByIndex(i),
strFormat)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = Format(cSD1.KeyByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
Else
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = cSD1.KeyByIndex(i)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = cSD1.KeyByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
End If

End If 'If bSortDescOnCount Or bSortAscOnCount

MakeFrequencyArray = arrReturn

End Function


RBS


"RB Smissaert" wrote in message
...
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


RB Smissaert

Top 5 most recurrent values in range.
 
I had to edit your code a bit to make it work:

Sub GetTop5()

Dim rngSource As Range ' the source range to work with
Dim celX As Range ' looping cell variable
Dim strLast As String ' remember last value string: for counting
Dim iLastRow As Long ' remember last row: for counting
Dim LR As Long

LR = Cells(65536, 1).End(xlUp).Row
Set rngSource = Range(Cells(1), Cells(LR, 2)) ' the range to work with

' 1) Sort on Column A
rngSource.Sort Key1:=Range("A1"), _
Order1:=xlAscending, _
Header:=xlNo, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom

' 2) Count frequency
' -- the duplicated ones will get count 0, so
' when sort on the count, they will appear at the end
For Each celX In Intersect(rngSource, Range("A:A")) ' loop through
Column A
If celX.Value = strLast Then
Cells(iLastRow, 2).Value = Cells(iLastRow, 2).Value + 1
celX.Offset(0, 1) = 0 ' the duplicate row will count as 0
Else
celX.Offset(0, 1) = 1 ' the first row of unique value
iLastRow = celX.Row ' remember this as the last row
strLast = celX.Value ' remember this as the last value
End If
Next celX

' 3) Sort on Frequency, then Value
rngSource.Sort Key1:=Range("B1"), _
Order1:=xlDescending, _
Key2:=Range("A1"), _
Order1:=xlAscending, _
Header:=xlNo, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom

' The results will be listed in the order of
' a) the frequency (column B) in descending order
' b) for the same frequency: the value (column A) in ascending order

End Sub

Now copy range range A1:A15 and paste down to row 65520 and then run the
same code and compare the speed with the code I posted.
I know that it is not relevant for small ranges but worth to bear in mind
that it can be done a lot faster.


RBS



"AndrewCerritos" wrote in message
...
Here is my take on this. Briefly:
(1) the values is string type, in column A of worksheet "top5"
(2) the range is known (otherwise have to check the last row containing
value)
(3) if you need to keep the original data and order, copy the value into
"top5" worksheet.
(4) I am using the Sort object
(5) Obviously, the routine can be further optimized

Private Sub GetTop5()
Dim rngSource As Range ' the source range to work with
Dim celX As Range ' looping cell variable
Dim strLast As String ' remember last value string: for counting
Dim iLastRow As Long ' remember last row: for counting

Worksheets("top5").Activate ' the worksheet to work on
Set rngSource = ActiveSheet.[A1:B15] ' the range to work with

' 1) Sort on Column A
With ActiveWorkbook.ActiveSheet.Sort
.SortFields.Clear ' clear the sorting fields
.SortFields.Add Key:=Range("A1"), Order:=xlAscending
.SetRange rngSource ' the range to sort on
.Header = xlNo ' NO: we don't have headers
.MatchCase = False ' NOT case-sensitive
.Orientation = xlTopToBottom ' sort by row
.SortMethod = xlPinYin ' based on sound (not strokes)
.Apply ' do the soring
End With

' 2) Count frequency
' -- the duplicated ones will get count 0, so
' when sort on the count, they will appear at the end
strLast = "" ' start with impossible value
iLastRow = 0 ' start with non-existing row
For Each celX In Intersect(rngSource, Range("A:A")) ' loop through
column A
If celX.Value = strLast Then
Cells(iLastRow, 2).Value = Cells(iLastRow, 2).Value + 1
celX.Offset(0, 1) = 0 ' the duplicate row will count as 0
Else
celX.Offset(0, 1) = 1 ' the first row of unique value
iLastRow = celX.Row ' remember this as the last row
strLast = celX.Value ' remember this as the last value
End If
Next celX

' 3) Sort on Frequency, then Value
'
With ActiveWorkbook.ActiveSheet.Sort
.SortFields.Clear ' clear the sorting fields
.SortFields.Add Key:=Range("B1"), Order:=xlDescending
.SortFields.Add Key:=Range("A1"), Order:=xlAscending
.SetRange rngSource ' the range to sort on
.Header = xlNo ' NO: we don't have headers
.MatchCase = False ' NOT case-sensitive
.Orientation = xlTopToBottom ' sort by row
.SortMethod = xlPinYin ' based on sound (not strokes)
.Apply ' sort it
End With

' The results will be listed in the order of
' a) the frequency (column B) in descending order
' b) for the same frequency: the value (column A) in ascending
order
End Sub


"RB Smissaert" wrote:

If you don't need the rank and percentage in the output then you could
leave
those lines out and do:

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 2)

If Len(strFormat) 0 Then
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = Format(cSD2.ItemByIndex(i),
strFormat)
'for some reason this is needed to avoid a currency sign in
front
of the number

'------------------------------------------------------------------------------
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = Format(cSD2.ItemByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
Next i
End If
Else
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = cSD2.ItemByIndex(i)
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = cSD2.ItemByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
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 2)

If Len(strFormat) 0 Then
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = Format(cSD1.KeyByIndex(i),
strFormat)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = Format(cSD1.KeyByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
Else
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = cSD1.KeyByIndex(i)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = cSD1.KeyByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
End If

End If 'If bSortDescOnCount Or bSortAscOnCount

MakeFrequencyArray = arrReturn

End Function


RBS


"RB Smissaert" wrote in message
...
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



AndrewCerritos

Top 5 most recurrent values in range.
 
That's cool.

AC

"RB Smissaert" wrote:

I had to edit your code a bit to make it work:

Sub GetTop5()

Dim rngSource As Range ' the source range to work with
Dim celX As Range ' looping cell variable
Dim strLast As String ' remember last value string: for counting
Dim iLastRow As Long ' remember last row: for counting
Dim LR As Long

LR = Cells(65536, 1).End(xlUp).Row
Set rngSource = Range(Cells(1), Cells(LR, 2)) ' the range to work with

' 1) Sort on Column A
rngSource.Sort Key1:=Range("A1"), _
Order1:=xlAscending, _
Header:=xlNo, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom

' 2) Count frequency
' -- the duplicated ones will get count 0, so
' when sort on the count, they will appear at the end
For Each celX In Intersect(rngSource, Range("A:A")) ' loop through
Column A
If celX.Value = strLast Then
Cells(iLastRow, 2).Value = Cells(iLastRow, 2).Value + 1
celX.Offset(0, 1) = 0 ' the duplicate row will count as 0
Else
celX.Offset(0, 1) = 1 ' the first row of unique value
iLastRow = celX.Row ' remember this as the last row
strLast = celX.Value ' remember this as the last value
End If
Next celX

' 3) Sort on Frequency, then Value
rngSource.Sort Key1:=Range("B1"), _
Order1:=xlDescending, _
Key2:=Range("A1"), _
Order1:=xlAscending, _
Header:=xlNo, _
OrderCustom:=1, _
MatchCase:=False, _
Orientation:=xlTopToBottom

' The results will be listed in the order of
' a) the frequency (column B) in descending order
' b) for the same frequency: the value (column A) in ascending order

End Sub

Now copy range range A1:A15 and paste down to row 65520 and then run the
same code and compare the speed with the code I posted.
I know that it is not relevant for small ranges but worth to bear in mind
that it can be done a lot faster.


RBS



"AndrewCerritos" wrote in message
...
Here is my take on this. Briefly:
(1) the values is string type, in column A of worksheet "top5"
(2) the range is known (otherwise have to check the last row containing
value)
(3) if you need to keep the original data and order, copy the value into
"top5" worksheet.
(4) I am using the Sort object
(5) Obviously, the routine can be further optimized

Private Sub GetTop5()
Dim rngSource As Range ' the source range to work with
Dim celX As Range ' looping cell variable
Dim strLast As String ' remember last value string: for counting
Dim iLastRow As Long ' remember last row: for counting

Worksheets("top5").Activate ' the worksheet to work on
Set rngSource = ActiveSheet.[A1:B15] ' the range to work with

' 1) Sort on Column A
With ActiveWorkbook.ActiveSheet.Sort
.SortFields.Clear ' clear the sorting fields
.SortFields.Add Key:=Range("A1"), Order:=xlAscending
.SetRange rngSource ' the range to sort on
.Header = xlNo ' NO: we don't have headers
.MatchCase = False ' NOT case-sensitive
.Orientation = xlTopToBottom ' sort by row
.SortMethod = xlPinYin ' based on sound (not strokes)
.Apply ' do the soring
End With

' 2) Count frequency
' -- the duplicated ones will get count 0, so
' when sort on the count, they will appear at the end
strLast = "" ' start with impossible value
iLastRow = 0 ' start with non-existing row
For Each celX In Intersect(rngSource, Range("A:A")) ' loop through
column A
If celX.Value = strLast Then
Cells(iLastRow, 2).Value = Cells(iLastRow, 2).Value + 1
celX.Offset(0, 1) = 0 ' the duplicate row will count as 0
Else
celX.Offset(0, 1) = 1 ' the first row of unique value
iLastRow = celX.Row ' remember this as the last row
strLast = celX.Value ' remember this as the last value
End If
Next celX

' 3) Sort on Frequency, then Value
'
With ActiveWorkbook.ActiveSheet.Sort
.SortFields.Clear ' clear the sorting fields
.SortFields.Add Key:=Range("B1"), Order:=xlDescending
.SortFields.Add Key:=Range("A1"), Order:=xlAscending
.SetRange rngSource ' the range to sort on
.Header = xlNo ' NO: we don't have headers
.MatchCase = False ' NOT case-sensitive
.Orientation = xlTopToBottom ' sort by row
.SortMethod = xlPinYin ' based on sound (not strokes)
.Apply ' sort it
End With

' The results will be listed in the order of
' a) the frequency (column B) in descending order
' b) for the same frequency: the value (column A) in ascending
order
End Sub


"RB Smissaert" wrote:

If you don't need the rank and percentage in the output then you could
leave
those lines out and do:

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 2)

If Len(strFormat) 0 Then
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = Format(cSD2.ItemByIndex(i),
strFormat)
'for some reason this is needed to avoid a currency sign in
front
of the number

'------------------------------------------------------------------------------
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = Format(cSD2.ItemByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
Next i
End If
Else
If bSortDescOnCount Then
For i = 0 To lcSD2Count - 1
arrReturn(lcSD2Count - i, 1) = cSD2.ItemByIndex(i)
arrReturn(lcSD2Count - i, 2) = CLng(cSD2.KeyByIndex(i))
Next i
Else
For i = 0 To lcSD2Count - 1
arrReturn(i + 1, 1) = cSD2.ItemByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD2.KeyByIndex(i))
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 2)

If Len(strFormat) 0 Then
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = Format(cSD1.KeyByIndex(i),
strFormat)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = Format(cSD1.KeyByIndex(i), strFormat)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
Else
If bSortDescOnItem Then
For i = 0 To lcSD1Count - 1
arrReturn(lcSD1Count - i, 1) = cSD1.KeyByIndex(i)
arrReturn(lcSD1Count - i, 2) = CLng(cSD1.ItemByIndex(i))
Next i
Else
For i = 0 To lcSD1Count - 1
arrReturn(i + 1, 1) = cSD1.KeyByIndex(i)
arrReturn(i + 1, 2) = CLng(cSD1.ItemByIndex(i))
Next i
End If
End If

End If 'If bSortDescOnCount Or bSortAscOnCount

MakeFrequencyArray = arrReturn

End Function


RBS


"RB Smissaert" wrote in message
...
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:



All times are GMT +1. The time now is 05:25 PM.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
ExcelBanter.com