代码之家  ›  专栏  ›  技术社区  ›  Ahmad

如何将变量数组转换为范围?

  •  4
  • Ahmad  · 技术社区  · 14 年前

    我有一个二维数组类型 Variant . 填充数组的大小和值是基于工作表中的数据生成的。需要对该数组进行进一步处理,主要是对多个值进行插值。我在用这个 interpolation function

    r as Variant )争论。下一行 nR = r.Rows.Count nR = Ubound(r)

    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
    

    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
    

    如何将内存中的变量数组转换为一个范围,以便用于插值函数(不输出到工作表)

    回答

    更改的插值函数检查 TypeName 并设置 nR

    值得注意的是 VarType VarType(Variant()) VarType(Range) 返回相同的值(即vbArray),无法用于消除数组与范围之间的歧义

    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 
    
    2 回复  |  直到 13 年前
        1
  •  3
  •   Mike Woodhouse    14 年前

    好吧,您不能创建一个范围对象,它在某种程度上不引用工作簿中的工作表位置。它可以是动态的,比如一个名为=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
    
        2
  •  1
  •   MikeD    14 年前

    下面是一个在新工作表中创建范围的函数。您可以通过添加另一个range参数来修改此函数,以提供容纳数组的单元格范围的起点。

    Function Array2Range(MyArray() As Variant) As Range
    Dim X As Integer, Y As Integer
    Dim Idx As Integer, Jdx As Integer
    Dim TmpSht As Worksheet, TmpRng As Range, PrevRng As Range
    
        X = UBound(MyArray, 1) - LBound(MyArray, 1)
        Y = UBound(MyArray, 2) - LBound(MyArray, 2)
    
        Set PrevRng = Selection
        Set TmpSht = ActiveWorkbook.Worksheets.Add
        Set TmpRng = TmpSht.[A1]
    
    
        For Idx = 0 To X
            For Jdx = 0 To Y
                TmpRng(Idx + 1, Jdx + 1) = MyArray(LBound(MyArray, 1) + Idx, LBound(MyArray, 2) + Jdx)
            Next Jdx
        Next Idx
    
        Set Array2Range = TmpRng.CurrentRegion
        PrevRng.Worksheet.Activate
    
    End Function
    
    Sub Test()
    Dim MyR As Range
    Dim MyArr(3, 3) As Variant
    
    MyArr(0, 0) = "'000"
    MyArr(0, 1) = "'0-1" ' demo correct row/column
    MyArr(1, 0) = "'1-0" ' demo correct row/column
    MyArr(1, 1) = 111
    MyArr(2, 2) = 222
    MyArr(3, 3) = 333
    
    Set MyR = Array2Range(MyArr) ' to range
    Range2Array MyR, MyOther     ' and back
    
    End Sub
    

    Sub Range2Array(MyRange As Range, ByRef MyArr() As Variant)
    Dim X As Integer, Y As Integer
    Dim Idx As Integer, Jdx As Integer
    Dim MyArray() As Variant, PrevRng As Range
    
        X = MyRange.CurrentRegion.Rows.Count - 1
        Y = MyRange.CurrentRegion.Columns.Count - 1
        ReDim MyArr(X, Y)
    
        For Idx = 0 To X
            For Jdx = 0 To Y
                MyArr(Idx, Jdx) = MyRange(Idx + 1, Jdx + 1)
            Next Jdx
        Next Idx
        MyRange.Worksheet.Delete
    
    End Sub