Ahm*_*mad 5 excel vba excel-2007
I have a 2D array of type Variant. The size and values that populate the array are generated based on data within a worksheet. Further processing is required on this array, the primary being the interpolation of several values. I am using this interpolation function (I know about excel equivalent functions but a design choice was made not to use them) . The problem I am having is the that the Interpolation function requires a Range object.
I have already tried modifying the function to use a Variant (r as Variant) argument. The following line nR = r.Rows.Count can be replaced with nR = Ubound(r). While this works, I would also like to use this function normally within any worksheet and not change the function in any way.
Sub DTOP()
Dim term_ref() As Variant
' snip '
ReDim term_ref(1 To zeroRange.count, 1 To 2)
' values added to term_ref '
' need to interpolate x1 for calculated y1 '
x1 = Common.Linterp(term_ref, y1)
End Sub
Run Code Online (Sandbox Code Playgroud)
Interpolation Function
Function Linterp(r As Range, x As Double) As Double
Dim lR As Long, l1 As Long, l2 As Long
Dim nR As Long
nR = r.Rows.Count
' snipped for brevity '
End Function
Run Code Online (Sandbox Code Playgroud)
How do I convert my in-memory variant array to a Range so that it can be used for the interpolate function? (without outputting to a WorkSheet)
Answer
In short, the answer is you can't. A Range object must reference a worksheet.
The changed interpolation function checks the TypeName of the argument and sets the value of nR accordingly. Not the prettiest solution.
As a note, the VarType function proved useless in this situation since both VarType(Variant()) and VarType(Range) returned the same value (i.e vbArray) and could not be used to disambiguate an array from a range
Function Linterp(r As Variant, x As Variant) As Double
Dim lR As Long, l1 As Long, l2 As Long
Dim nR As Long
Dim inputType As String
inputType = TypeName(r)
' Update based on comment from jtolle
If TypeOf r Is Range Then
nR = r.Rows.Count
Else
nR = UBound(r) - LBound(r) 'r.Rows.Count
End If
' ....
End Function
Run Code Online (Sandbox Code Playgroud)
AFAIK,您无法创建不以某种方式引用工作簿的工作表位置的 Range 对象。它可以是动态的,例如 Named =OFFSET() 函数,但它必须与某处的工作表相关联。
为什么不改变插值函数呢?保持 Linterp 签名不变,但将其放入在数组上插值的函数的包装器中。
像这样的东西:
Function Linterp(rng As Range, x As Double) As Double
' R is a two-column range containing known x, known y
' This is now just a wrapper function, extracting the range values into a variant
Linterp = ArrayInterp(rng.Value, x)
End Function
Function ArrayInterp(r As Variant, x As Double) As Double
Dim lR As Long
Dim l1 As Long, l2 As Long
Dim nR As Long
nR = UBound(r) ' assumes arrays are all 1-based
If nR = 1 Then
' code as given would return 0, better would be to either return
' the only y-value we have (assuming it applies for all x values)
' or perhaps to raise an error.
ArrayInterp = r(1, 2)
Exit Function
End If
If x < r(1, 1) Then ' x < xmin, extrapolate'
l1 = 1
l2 = 2
ElseIf x > r(nR, 2) Then ' x > xmax, extrapolate'
l2 = nR
l1 = l2 - 1
Else
' a binary search might be better here if the arrays are large'
For lR = 1 To nR
If r(lR, 1) = x Then ' no need to interpolate if x is a point in the array'
ArrayInterp = r(lR, 2)
Exit Function
ElseIf r(lR, 2) > x Then ' x is between tabulated values, interpolate'
l2 = lR
l1 = lR - 1
Exit For
End If
Next
End If
ArrayInterp = r(l1, 2) _
+ (r(l2, 2) - r(l1, 2)) _
* (x - r(l1, 1)) _
/ (r(l2, 1) - r(l1, 1))
End Function
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22514 次 |
| 最近记录: |