Option Explicit
Enum Input_Columns
icMatch = 1
icTeamName
icPoints
End Enum
Enum Output_Columns
ocLBound = 0
ocRank = 1
ocTeamName
ocPoints
ocWins
ocDefeats
ocUBound
End Enum
Function sbMatchListToRankTable(rInput As Range) As Variant
'Takes an input list of matches and creates an output like
'Rank Position Team name Points Wins Defeats
' 1 Finstock 16 6 1
' 2 Droogs 6 3 2
' 3 RoxStars 6 2 1
' 4 Suspects 6 2 2
'You need to array-enter (enter with CTRL + ALT + F9) this function
'into a range of 5 columns and a sufficient number of rows.
Dim i As Long
Dim bLowerRank As Boolean
Dim dPointsCurrent As Double, dPointsPrevious As Double
Dim lMatchCurrent As Long, lMatchPrevious As Long
Dim sTeamNameCurrent As String, sTeamNamePrevious As String
Dim v As Variant, vR As Variant, vC As Variant, vP As Variant
Dim oRank As Object, oPoints As Object, oWins As Object, oDefeats As Object
Set oRank = CreateObject("Scripting.Dictionary")
Set oPoints = CreateObject("Scripting.Dictionary")
Set oWins = CreateObject("Scripting.Dictionary")
Set oDefeats = CreateObject("Scripting.Dictionary")
lMatchPrevious = 0
For i = 2 To rInput.Rows.Count
sTeamNameCurrent = rInput.Cells(i, icTeamName)
dPointsCurrent = rInput.Cells(i, icPoints)
oPoints(sTeamNameCurrent) = oPoints(sTeamNameCurrent) + dPointsCurrent
lMatchCurrent = rInput.Cells(i, icMatch)
If lMatchCurrent = lMatchPrevious Then
If dPointsPrevious > dPointsCurrent Then
oWins(sTeamNamePrevious) = oWins(sTeamNamePrevious) + 1
oDefeats(sTeamNameCurrent) = oDefeats(sTeamNameCurrent) + 1
ElseIf dPointsPrevious < dPointsCurrent Then
oWins(sTeamNameCurrent) = oWins(sTeamNameCurrent) + 1
oDefeats(sTeamNamePrevious) = oDefeats(sTeamNamePrevious) + 1
Else
'No dealing with ties
End If
Else
dPointsPrevious = dPointsCurrent
lMatchPrevious = lMatchCurrent
sTeamNamePrevious = sTeamNameCurrent
End If
Next i
i = 1
For Each v In oPoints.keys
If i = 1 Then
oRank("First") = v
oRank(v) = "None"
Else
vC = "First"
vP = vC
bLowerRank = True
If (oPoints(v) > oPoints(oRank(vC))) Or _
(oPoints(v) = oPoints(oRank(vC)) And oWins(v) > oWins(oRank(vC))) Or _
(oPoints(v) = oPoints(oRank(vC)) And oWins(v) = oWins(oRank(vC)) And oDefeats(v) < oDefeats(oRank(vC))) Then
bLowerRank = False
End If
Do While bLowerRank
vP = vC
vC = oRank(vC)
If oRank(vC) = "None" Then Exit Do
bLowerRank = True
If (oPoints(v) > oPoints(oRank(vC))) Or _
(oPoints(v) = oPoints(oRank(vC)) And oWins(v) > oWins(oRank(vC))) Or _
(oPoints(v) = oPoints(oRank(vC)) And oWins(v) = oWins(oRank(vC)) And oDefeats(v) < oDefeats(oRank(vC))) Then
bLowerRank = False
End If
Loop
If bLowerRank Then
oRank(vC) = v
oRank(v) = "None"
Else
oRank(v) = oRank(vC)
oRank(vC) = v
End If
End If
i = i + 1
Next v
ReDim vR(1 To oPoints.Count + 1, ocLBound + 1 To ocUBound - 1) As Variant
ReDim vR(1 To Application.Caller.Rows.Count, ocLBound + 1 To ocUBound - 1) As Variant
vR(1, ocRank) = "Rank"
vR(1, ocTeamName) = "Team Name"
vR(1, ocPoints) = "Points"
vR(1, ocWins) = "Wins"
vR(1, ocDefeats) = "Defeats"
i = 2
vP = "First"
v = oRank(vP)
Do While v <> "None"
If vP <> "First" Then
If oPoints(v) = oPoints(vP) And oWins(v) = oWins(vP) And oDefeats(v) = oDefeats(vP) Then
vR(i, ocRank) = vR(i - 1, ocRank)
Else
vR(i, ocRank) = i - 1
End If
Else
vR(i, ocRank) = i - 1
End If
vR(i, ocTeamName) = v
vR(i, ocPoints) = oPoints(v)
vR(i, ocWins) = oWins(v)
vR(i, ocDefeats) = oDefeats(v)
i = i + 1
vP = v
v = oRank(v)
Loop
Do While i <= Application.Caller.Rows.Count
vR(i, ocRank) = ""
vR(i, ocTeamName) = ""
vR(i, ocPoints) = ""
vR(i, ocWins) = ""
vR(i, ocDefeats) = ""
i = i + 1
Loop
sbMatchListToRankTable = vR
End Function