Excel UDF用于整个范围而不是每个单元格

时间:2016-08-05 22:45:57

标签: excel vba excel-vba

我的工作簿中有以下UDF:

Function GetRoundTime(Shp1 As String, Res1 As String, Shp2 As String, Res2 As String, Sht As String) As String
    Dim i As Long
    Dim TempSheet As Worksheet
    Set TempSheet = Workbooks("odds_datalog.xlsm").Worksheets(Sht)
    'Need to find out what the last row is instead of hardcoding it at 2000
    For i = 2 To 2000
        If TempSheet.Cells(i, "D").Value = Shp1 And TempSheet.Cells(i, "I").Value = Shp2 And TempSheet.Cells(i, "E").Value = Res1 And TempSheet.Cells(i, "J").Value = Res2 Then
            GetRoundTime = CStr(TempSheet.Cells(i, "K").Value)
            Exit Function
        End If
    Next i
    GetRoundTime = "Failed"
End Function


Function GetOdds(Shp1 As String, Res1 As String, Sht1 As String, Shp2 As String, Res2 As String, Sht2 As String) As String
    Dim LeftTime As String
    Dim TopTime As String
    LeftTime = GetRoundTime(Shp1, Res1, Shp2, Res2, Sht1)
    TopTime = GetRoundTime(Shp2, Res2, Shp1, Res1, Sht2)
    If LeftTime = "NoAttack" Then
        GetOdds = ""
    ElseIf LeftTime = "TimedOut" Then
        GetOdds = "Time (left)"
    ElseIf LeftTime = "SameShip" Then
        GetOdds = ""
    ElseIf LeftTime = "Failed" Then
        GetOdds = "Failed"
    ElseIf TopTime = "NoAttack" Then
        GetOdds = ""
    ElseIf TopTime = "TimedOut" Then
        GetOdds = "Time (top)"
    ElseIf TopTime = "SameShip" Then
        GetOdds = ""
    ElseIf TopTime = "Failed" Then
        GetOdds = "Failed"
    Else
        GetOdds = Sqr(Val(TopTime) / Val(LeftTime))
    End If
End Function

并且,在每个单元格中调用GetOdds函数:

=GetOdds($A20,$B20,"log_hgn_hgn",D$1,D$2,"log_hgn_hgn")
=GetOdds($A21,$B21,"log_hgn_hgn",D$1,D$2,"log_hgn_hgn")
=GetOdds($A22,$B22,"log_hgn_hgn",D$1,D$2,"log_hgn_hgn")

等等。

然而,重新计算非常缓慢。我听说输入一系列单元可以提高性能。这是真的?我如何改变代码来做到这一点?谢谢!

[编辑]

这是其中一个工作表的样子。

http://imgur.com/a/XMoiS

1 个答案:

答案 0 :(得分:1)

我不确定“输入一系列单元格”究竟是什么意思,但是函数中最慢的部分就在这里:

'Need to find out what the last row is instead of hardcoding it at 2000
For i = 2 To 2000
    If TempSheet.Cells(i, "D").Value = Shp1 And TempSheet.Cells(i, "I").Value = Shp2 And TempSheet.Cells(i, "E").Value = Res1 And TempSheet.Cells(i, "J").Value = Res2 Then
        GetRoundTime = CStr(TempSheet.Cells(i, "K").Value)
        Exit Function
    End If
Next i

您正在重复访问工作表,这是。通过一次将所有值拉入数组并使用数组,您可能会获得最大的性能提升。这样的事情应该会显着加快速度:

Function GetRoundTime(Shp1 As String, Res1 As String, Shp2 As String, _
                      Res2 As String, Sht As String) As String
    With Workbooks("odds_datalog.xlsm").Worksheets(Sht)
        Dim lastRow As Long, values() As Variant
        lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
        values = .Range(.Cells(2, 4), .Cells(lastRow, 11)).Value
        Dim i As Long
        For i = 1 To lastRow - 1
            If values(i, 1) = Shp1 And values(i, 6) = Shp2 And _ 
               values(i, 2) = Res1 And values(i, 7) = Res2 Then
                GetRoundTime = CStr(values(i, 8))
                Exit Function
            End If
        Next
    End With
    GetRoundTime = "Failed"
End Function