停止1乘n阵列转换为1维数组

时间:2016-09-12 04:19:16

标签: arrays excel vba excel-vba

下面是我编写的用于统一处理数组和范围的一些代码(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,在其上调用清理,您将拥有同一件事的两个副本:

enter image description here

然而,问题是sanitise ^ 2。

拨打sanitise两次会发生故障,但只有在单行呼叫时才会发生。多行:精细,单列:很好。

enter image description here

我知道它为什么会发生:在第一个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

2 个答案:

答案 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内传递数组,请参考下面的内容工作表;

enter image description here

答案 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