Option Explicit
Sub RankScoresBySection()
Dim dicSection As Object
Dim vItem As Variant
Dim wsData As Worksheet
Dim vSection As Variant
Dim rScore As Range
Dim rCell As Range
Dim Score As Variant
Dim Rnk As Double
Dim LastRow As Long
Dim i As Long
Application.ScreenUpdating = False
Set wsData = ActiveSheet
With wsData
If .FilterMode Then .ShowAllData
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
If LastRow > 1 Then
'Data exists
Else
MsgBox "No data exists!", vbExclamation
Exit Sub
End If
Set dicSection = CreateObject("Scripting.Dictionary")
dicSection.CompareMode = 1 'vbTextCompare
vSection = wsData.Range("A1:A" & LastRow).Value
For i = LBound(vSection) + 1 To UBound(vSection)
If Not dicSection.Exists(vSection(i, 1)) Then
dicSection(vSection(i, 1)) = ""
End If
Next i
On Error Resume Next
For Each vItem In dicSection.keys()
With wsData.UsedRange
.AutoFilter field:=1, Criteria1:=vItem
For i = 0 To 2
.AutoFilter field:=i + 2, Criteria1:=">0"
Set rScore = .Offset(1, i + 1).Resize(.Rows.Count - 1, 1).SpecialCells(xlCellTypeVisible)
If Err = 0 Then
For Each rCell In rScore
Score = rCell.Value
If Application.IsNumber(Score) Then
Rnk = WorksheetFunction.Rank(CDbl(Score), rScore)
rCell.Offset(, 3).Value = Rnk & GetOrdinalSuffixForRank(Rnk)
End If
Next rCell
Else
Err.Clear
End If
.AutoFilter field:=i + 2
Next i
.AutoFilter
End With
Next vItem
On Error GoTo 0
Application.ScreenUpdating = True
Set dicSection = Nothing
Set rScore = Nothing
Set rCell = Nothing
End Sub