将不连续的单元格视为用作 UDF 参数的单个范围
Treating noncontiguous cells as a single range used as argument of a UDF
我正在尝试使用两个数据集通过插值法构建收益率曲线:到期前的日历天数范围和另一个利率范围。
我在 VBA 上有一个内插利率的 UDF。它使用用户在 excel 工作表上 select 编辑的两个单元格范围作为参数。
我知道 Excel 要求这些范围由连续的单元格组成。
我想要做的是 select 工作表中的非连续单元格,并将其值用作 UDF 参数的范围。
更具体地说,我有两列数据用作范围。但有时我需要在每一列上跳过一个值,并将剩余的值用作我的 UDF 的范围。
我尝试在我的 UDF 中包含另外两个范围参数,并使用 union 方法将两个范围合并为一个范围,以便在我的代码中使用结果范围。没用。
****编辑
克里斯,
感谢您指出手表和即时 Windows。经过多次尝试,代码终于按我的预期运行,但仅针对 DC_1 和 taxas_1 范围使用单独的循环。
奇怪的是,如果我从循环内部删除 "If k > 1 Then" 语句,它将不起作用。所以我需要保留它,让它什么都不做。
我注意到间接函数不能使用像 (A1:A3,C2:C5) 这样的参数,所以我不能使用 indirect((A1:A3,C2:C5)) 作为参数自定义函数。不过,这是个小问题。
万一有人遇到类似问题 post,这里是我使用的代码。
Public Function Interplin_union(ByVal taxas_1 As Range, ByVal DC_1 As Range, ByVal dias As Integer) As Double
Dim tam1 As Long
Dim taxa1 As Double, taxa2 As Double, alfa As Double, d1 As Double, d2 As Double
Dim k As Long
Dim taxas As Variant
Dim DC As Variant
tam1 = taxas_1.Cells.Count
ReDim taxas(1 To tam1)
ReDim DC(1 To tam1)
Interplin_union = -1
Dim c As Range
k = 1
For Each c In DC_1
'taxas(k) = taxas_1(k)
DC(k) = c
If k > 1 Then
'Debug.Print DC(k)
If DC(k - 1) > DC(k) Then
Interplin_union = CVErr(xlErrNA)
Exit Function
End If
End If
k = k + 1
Next
k = 1
For Each c In taxas_1
taxas(k) = c
If k > 1 Then
'Debug.Print DC(k), taxas(k)
End If
k = k + 1
Next
For k = 1 To (tam1 - 1)
If ((DC(k) < dias) And (DC(k + 1) >= dias)) Then
taxa1 = taxas(k)
taxa2 = taxas(k + 1)
alfa = (taxa2 - taxa1) / (DC(k + 1) - DC(k))
Interplin_union = taxa1 + (alfa * (dias - DC(k)))
End If
Next k
If (dias <= DC(1)) Then
Interplin_union = taxas(1)
ElseIf dias > DC(tam1) Then
Interplin_union = taxas(tam1)
End If
End Function
你 可以 实际上循环遍历不连续范围的单元格。
就是说,许多范围属性在应用于不连续范围时,return 第一个连续子范围的 属性 值。
演示:
Dim cl as Range, SomeDiscontiguousRange as Range
Dim Rpt as String
Set SomeDiscontiguousRange = [A1:A3, C2:C5]
For each cl in SomeDiscontiguousRange
'Do something with cl, eg
Rpt = Rpt & "," & cl.Address
Next
Debug.Print Rpt 'returns the 7 cell addresses
Debug.Print SomeDiscontiguousRange.Rows.Count 'returns 3, the rows in the first sub-range
那么,如何将其应用到您的情况中呢?我建议两件事:
- 不要为您的 UDF 创建额外的参数,而是使用 Excel 公式联合运算符的强大功能 - 将不连续的范围括在公式中的方括号中。
- 如上所示循环不连续的范围以将数据映射到变体数组中。然后循环该数组以应用您的逻辑
演示 1
Function Demo(r as range) as Variant
Demo = r.Address
End Function
在这样的单元格中使用:=Demo((A1:A3,C2:C5))
注意双括号,这告诉 Excel 将 (A1:A3,C2:C5)
视为单个参数。
您的代码已重构以应用这些方法(以及一些其他优化)
Public Function Interplin_union(ByVal taxas_1 As Range, ByVal DC_1 As Range, ByVal dias As Integer) As Double
Dim tam1 As Long
Dim taxa1 As Double, taxa2 As Double, alfa As Double, d1 As Double, d2 As Double
Dim k As Long
Dim taxas As Variant
Dim DC As Variant
tam1 = taxas_1.Cells.Count
ReDim taxas(1 To tam1)
ReDim DC(1 To tam1)
Interplin_union = -1
Dim c As Range
k = 1
For Each c In DC_1
taxas(k) = taxas_1(k)
DC(k) = c
If k > 1 Then
Debug.Print DC(k - 1), DC(k)
If DC(k - 1) > DC(k) Then
Interplin_union = CVErr(xlErrNA)
Exit Function
End If
End If
k = k + 1
Next
For k = 1 To (tam1 - 1)
If ((DC(k) < dias) And (DC(k + 1) >= dias)) Then
taxa1 = taxas(k)
taxa2 = taxas(k + 1)
alfa = (taxa2 - taxa1) / (DC(k + 1) - DC(k))
Interplin_union = taxa1 + (alfa * (dias - DC(k)))
End If
Next k
If (dias <= DC(1)) Then
Interplin_union = taxas(1)
ElseIf dias > DC(tam1) Then
Interplin_union = taxas(tam1)
End If
End Function
旁注:
- 你对数据应用的函数逻辑我不做评论,我没有分析过
要访问不连续范围的每个范围的属性,首先循环遍历区域,然后遍历每个区域的单元格。例如
Dim Arr as Range, Cl as Range
For Each Arr in SomeDiscontiguousRange.Areas
Debug.Print Arr.Rows.Count
For Each Cl in Arr.Cells
Debug.Print Cl.Address
Next
Next
Excels 公式联合运算符是 ,
和交集运算符是 </code> (Space).<br>
试试 <code>=demo((C4:D7 C2:C12))
看看我的意思。 See this - "Under Reference operators" heading
- 您需要添加一些检查来验证范围形状,以防将意外的东西传递给 UDF
我正在尝试使用两个数据集通过插值法构建收益率曲线:到期前的日历天数范围和另一个利率范围。
我在 VBA 上有一个内插利率的 UDF。它使用用户在 excel 工作表上 select 编辑的两个单元格范围作为参数。
我知道 Excel 要求这些范围由连续的单元格组成。 我想要做的是 select 工作表中的非连续单元格,并将其值用作 UDF 参数的范围。
更具体地说,我有两列数据用作范围。但有时我需要在每一列上跳过一个值,并将剩余的值用作我的 UDF 的范围。
我尝试在我的 UDF 中包含另外两个范围参数,并使用 union 方法将两个范围合并为一个范围,以便在我的代码中使用结果范围。没用。
****编辑
克里斯, 感谢您指出手表和即时 Windows。经过多次尝试,代码终于按我的预期运行,但仅针对 DC_1 和 taxas_1 范围使用单独的循环。 奇怪的是,如果我从循环内部删除 "If k > 1 Then" 语句,它将不起作用。所以我需要保留它,让它什么都不做。
我注意到间接函数不能使用像 (A1:A3,C2:C5) 这样的参数,所以我不能使用 indirect((A1:A3,C2:C5)) 作为参数自定义函数。不过,这是个小问题。
万一有人遇到类似问题 post,这里是我使用的代码。
Public Function Interplin_union(ByVal taxas_1 As Range, ByVal DC_1 As Range, ByVal dias As Integer) As Double
Dim tam1 As Long
Dim taxa1 As Double, taxa2 As Double, alfa As Double, d1 As Double, d2 As Double
Dim k As Long
Dim taxas As Variant
Dim DC As Variant
tam1 = taxas_1.Cells.Count
ReDim taxas(1 To tam1)
ReDim DC(1 To tam1)
Interplin_union = -1
Dim c As Range
k = 1
For Each c In DC_1
'taxas(k) = taxas_1(k)
DC(k) = c
If k > 1 Then
'Debug.Print DC(k)
If DC(k - 1) > DC(k) Then
Interplin_union = CVErr(xlErrNA)
Exit Function
End If
End If
k = k + 1
Next
k = 1
For Each c In taxas_1
taxas(k) = c
If k > 1 Then
'Debug.Print DC(k), taxas(k)
End If
k = k + 1
Next
For k = 1 To (tam1 - 1)
If ((DC(k) < dias) And (DC(k + 1) >= dias)) Then
taxa1 = taxas(k)
taxa2 = taxas(k + 1)
alfa = (taxa2 - taxa1) / (DC(k + 1) - DC(k))
Interplin_union = taxa1 + (alfa * (dias - DC(k)))
End If
Next k
If (dias <= DC(1)) Then
Interplin_union = taxas(1)
ElseIf dias > DC(tam1) Then
Interplin_union = taxas(tam1)
End If
End Function
你 可以 实际上循环遍历不连续范围的单元格。
就是说,许多范围属性在应用于不连续范围时,return 第一个连续子范围的 属性 值。
演示:
Dim cl as Range, SomeDiscontiguousRange as Range
Dim Rpt as String
Set SomeDiscontiguousRange = [A1:A3, C2:C5]
For each cl in SomeDiscontiguousRange
'Do something with cl, eg
Rpt = Rpt & "," & cl.Address
Next
Debug.Print Rpt 'returns the 7 cell addresses
Debug.Print SomeDiscontiguousRange.Rows.Count 'returns 3, the rows in the first sub-range
那么,如何将其应用到您的情况中呢?我建议两件事:
- 不要为您的 UDF 创建额外的参数,而是使用 Excel 公式联合运算符的强大功能 - 将不连续的范围括在公式中的方括号中。
- 如上所示循环不连续的范围以将数据映射到变体数组中。然后循环该数组以应用您的逻辑
演示 1
Function Demo(r as range) as Variant
Demo = r.Address
End Function
在这样的单元格中使用:=Demo((A1:A3,C2:C5))
注意双括号,这告诉 Excel 将 (A1:A3,C2:C5)
视为单个参数。
您的代码已重构以应用这些方法(以及一些其他优化)
Public Function Interplin_union(ByVal taxas_1 As Range, ByVal DC_1 As Range, ByVal dias As Integer) As Double
Dim tam1 As Long
Dim taxa1 As Double, taxa2 As Double, alfa As Double, d1 As Double, d2 As Double
Dim k As Long
Dim taxas As Variant
Dim DC As Variant
tam1 = taxas_1.Cells.Count
ReDim taxas(1 To tam1)
ReDim DC(1 To tam1)
Interplin_union = -1
Dim c As Range
k = 1
For Each c In DC_1
taxas(k) = taxas_1(k)
DC(k) = c
If k > 1 Then
Debug.Print DC(k - 1), DC(k)
If DC(k - 1) > DC(k) Then
Interplin_union = CVErr(xlErrNA)
Exit Function
End If
End If
k = k + 1
Next
For k = 1 To (tam1 - 1)
If ((DC(k) < dias) And (DC(k + 1) >= dias)) Then
taxa1 = taxas(k)
taxa2 = taxas(k + 1)
alfa = (taxa2 - taxa1) / (DC(k + 1) - DC(k))
Interplin_union = taxa1 + (alfa * (dias - DC(k)))
End If
Next k
If (dias <= DC(1)) Then
Interplin_union = taxas(1)
ElseIf dias > DC(tam1) Then
Interplin_union = taxas(tam1)
End If
End Function
旁注:
- 你对数据应用的函数逻辑我不做评论,我没有分析过
要访问不连续范围的每个范围的属性,首先循环遍历区域,然后遍历每个区域的单元格。例如
Dim Arr as Range, Cl as Range For Each Arr in SomeDiscontiguousRange.Areas Debug.Print Arr.Rows.Count For Each Cl in Arr.Cells Debug.Print Cl.Address Next Next
Excels 公式联合运算符是
,
和交集运算符是</code> (Space).<br> 试试 <code>=demo((C4:D7 C2:C12))
看看我的意思。 See this - "Under Reference operators" heading- 您需要添加一些检查来验证范围形状,以防将意外的东西传递给 UDF