Option Explicit
Sub SumByRank()
Dim vRank As Variant
Dim vTB3 As Variant
Dim vMPValues As Variant
Dim r As Long
Dim SumRank As Long
Dim CritValues As Variant
Dim sRow As Long
Dim LastRow As Long
Dim Calc As Long
Dim ColCnt As Long
Dim dblOutput() As Double
Dim eRow As Long
Dim i As Long
Dim j As Long
Const RankRange As String = "AX:BH"
Const TopBotRange As String = "BV:CF"
Const MultiplyRange As String = "Z:AJ"
Const CalcSheet As String = "Calc"
Const StartRow As Long = 4
Const OutPutRange As String = "CH:CH"
With Application
Calc = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ThisWorkbook.Worksheets(CalcSheet)
LastRow = .Cells(.Rows.Count, .Range(RankRange).Column).End(3).Row
ColCnt = .Range(RankRange).Columns.Count
vMPValues = .Range(MultiplyRange).Cells(1).Offset(StartRow - 1).Resize(LastRow - StartRow + 1, ColCnt).Value2
vRank = .Range(RankRange).Cells(1).Offset(StartRow - 1).Resize(LastRow - StartRow + 1, ColCnt).Value2
vTB3 = .Range(TopBotRange).Cells(1).Offset(StartRow - 1).Resize(LastRow - StartRow + 1, ColCnt).Value2
End With
eRow = UBound(vRank, 1)
ReDim dblOutput(1 To eRow)
With Application
For r = 1 To eRow
CritValues = .Index(vRank, r, 0)
SumRank = .Sum(CritValues)
If r < eRow Then
If SumRank >= 45 Then
i = 1: j = r + 1
Do While i <= 5
dblOutput(j) = SumTopBot3(CritValues, .Index(vTB3, j, 0), .Index(vMPValues, j, 0))
If j = eRow Then Exit For
i = i + 1: j = j + 1
Loop
r = j - 1
End If
End If
Next
End With
With ThisWorkbook.Worksheets(CalcSheet).Range(OutPutRange).Cells(StartRow).Resize(eRow)
.Value = Application.Transpose(dblOutput)
.Replace "0", vbNullString, 1
End With
With Application
.Calculation = Calc
.ScreenUpdating = True
End With
End Sub
Private Function SumTopBot3(ByVal RankValues As Variant, ByVal SumValues As Variant, ByVal MultiplyValues As Variant) As Double
Dim i As Long
Dim j As Long
Dim t As Double
Dim d As Double
Dim SV() As Double
Dim RV() As Long
Dim MV() As Double
ReDim SV(1 To UBound(RankValues))
ReDim RV(1 To UBound(RankValues))
ReDim MV(1 To UBound(RankValues))
For i = LBound(RankValues) To UBound(RankValues)
If Len(RankValues(i)) Then
j = j + 1
RV(j) = RankValues(i)
If Not IsError(SumValues(i)) Then
SV(j) = SumValues(i)
Else
SV(j) = 0
End If
If Not IsError(MultiplyValues(i)) Then
MV(j) = MultiplyValues(i)
Else
MV(j) = 1
End If
End If
Next
If j Then
ReDim Preserve RV(1 To j)
ReDim Preserve SV(1 To j)
ReDim Preserve MV(1 To j)
For i = LBound(RV) To UBound(RV) - 1
For j = i + 1 To UBound(RV)
If Val(RV(j)) > Val(RV(i)) Then
t = Val(RV(i))
d = SV(i)
RV(i) = RV(j)
RV(j) = t
SV(i) = SV(j)
SV(j) = d
d = MV(i)
MV(i) = MV(j)
MV(j) = d
End If
Next
Next
'replace * with / if you want to divide
SumTopBot3 = (SV(1) * -1 * MV(1)) + (SV(2) * -1 * MV(2)) + (SV(3) * -1 * MV(3)) + SV(UBound(SV)) + SV(UBound(SV) - 1) + SV(UBound(SV) - 2)
End If
End Function
I'd like to change the above code so that the first value in BV:CF holds as addends for all five sums, and still be divided by the values in Z:AJ. So the result would vary because the values in Z:AJ vary, but Z:AJ is the denominator of the same numerator for all five days. As it is now, the rank ranges are being held constant but being applied to varying BV:CF values. How would I change the above code?
Bookmarks