下面是我编写的用于统一处理数组和范围的一些代码(Accepting a range as an array parameter)。它包含一个名为sanitise
的函数,它可以作为一个函数,你可以调用一些2D数字集合A
,并获得与二元数组2D数据相同的数字。
Public Function item(ByRef A As Variant, i As Integer, j As Integer) As Double
If TypeName(A) = "Range" Then
item = A.Cells(i, j)
Else
item = A(i, j)
End If
End Function
Public Function rows(ByRef A As Variant) As Integer
If TypeName(A) = "Range" Then
rows = A.rows.Count
Else
rows = UBound(A, 1) - LBound(A, 1) + 1
End If
End Function
Public Function cols(ByRef A As Variant) As Integer
If TypeName(A) = "Range" Then
cols = A.columns.Count
Else
cols = UBound(A, 2) - LBound(A, 2) + 1
End If
End Function
Public Function sanitise(ByRef A As Variant) As Double()
Debug.Print TypeName(A)
If TypeName(A) = "Double()" Then
sanitise = A
Else
Debug.Print rows(A)
Dim B() As Double
ReDim B(1 To rows(A), 1 To cols(A))
Dim i As Integer, j As Integer
For i = 1 To rows(A)
For j = 1 To cols(A)
B(i, j) = item(A, i, j)
Next j
Next i
sanitise = B
End If
End Function
实施完全符合您的预期:在工作表中选择一个范围,比如A1:B2
,在其上调用清理,您将拥有同一件事的两个副本:
然而,问题是sanitise
^ 2。
拨打sanitise
两次会发生故障,但只有在单行呼叫时才会发生。多行:精细,单列:很好。
我知道它为什么会发生:在第一个sanitise
之后,Excel会忘记返回的是什么形状数组。 (它也会忘记类型:而不是Double()
第二个sanitise
的输入是Variant()
)
有人知道如何解决这个问题吗?
虽然我不太可能想连续两次使用sanitise
,但上面的例子说明了为什么沿二维数组组合两个函数很困难
注意:只有在从工作表中调用sanitise
时才会出现此问题。
更新,我已经弄清楚了:对于工作表1D存储与行同义,因此需要考虑
我的最终版本:
Public Function get_2D(ByRef A As Variant) As Double()
'turns various forms of input into a 2D array of Doubles
Dim result() As Double
Dim i As Integer
If TypeOf A Is Range Or dims(A) = 2 Then
ReDim result(1 To rows(A), 1 To cols(A))
Dim j As Integer
For i = 1 To rows(A)
For j = 1 To cols(A)
result(i, j) = item(A, i, j)
Next j
Next i
Else
'1D storage is treated as a row
ReDim result(1 To 1, 1 To rows(A)) 'rows(A) gets length of the first axis
For i = 1 To rows(A)
result(1, i) = A(i)
Next i
End If
sanitise = result
End Function
dims
是一个返回数组维数的函数:https://support.microsoft.com/en-us/kb/152288
答案 0 :(得分:2)
我认为这与您的规范有些一致,它有解决您演示的单行问题的好处。它会用于您的目的吗?
Function sanitise_sugg(inp As Variant) As Variant
Dim result As Variant
If TypeOf inp Is Object Then
result = inp.Value
Else
result = inp
End If
sanitise_sugg = result
End Function
编辑:退一步我觉得你应该将手头的任务分成两部分:首先使用" sanitise_sugg"使用excel范围和excel-vba阵列可以互换。然后,如果您特殊需要请求输入特定是某种类型的双精度数组,请编写一个单独的函数来测试,如果可能的话,将变量输入强制转换为此类型。
编辑2:向前迈出一步,让我声称,如果输入到Function sanitise_sugg(inp As Variant) As Variant
的元素包含来自vba中的双精度数,或者来自excel表的数字值包含单元格,则它符合要求的规范。 Public Function sanitise(ByRef A As Variant) As Double()
编辑3:要查看函数如何跟踪其输入数组布局,而不依赖于行向量,列向量或完整矩阵,无论是从excel范围还是从VBA内传递数组,请参考下面的内容工作表;
答案 1 :(得分:0)
我想不出任何实际用途,除非你对双打的二维阵列做了很多计算,所以如果你提供更多关于你想要做什么的信息,我们可能会更容易推荐一些东西/更好/更有效等。
当范围内有多个单元格时, .Value
和.Value2
会返回2D Variant数组:
v = [a1:b1].Value2 ' Variant/Variant(1 to 1, 1 to 2)
v = [a1:a2].Value2 ' Variant/Variant(1 to 2, 1 to 1)
v = [a1].Value2 ' Variant/Double
所以天真的方法可能是这样的:
Function to2D(v) As Double()
'Debug.Print TypeName(v), VarType(v)
Dim d2() As Double, r As Long, c As Long
If IsArray(v) Then
If TypeOf v Is Range Then v = v.Value2
ReDim d2(1 To UBound(v, 1), 1 To UBound(v, 2))
For r = 1 To UBound(v, 1)
For c = 1 To UBound(v, 2)
If IsNumeric(v(r, c)) Then d2(r, c) = v(r, c)
Next c
Next r
Else
ReDim d2(1 To 1, 1 To 1)
If IsNumeric(v) Then d2(1, 1) = v
End If
to2D = d2
End Function
并测试:
d2 = to2D([a1:b2])
d2 = to2D([a1:b1])
d2 = to2D([a1:a2])
d2 = to2D([a1])
d2 = to2D(1)
d2 = to2D([{" 1 ";" 2.0 "}]) ' works with strings too
d2 = to2D([{1,2;3,4}])
'd2 = to2D([{1,2}]) ' doesn't work with 1D arrays