如何在excel vba中获取数组中元素的子集?

1rhkuytd  于 2023-03-24  发布在  其他
关注(0)|答案(3)|浏览(378)

如何在excel vba中获取数组中的第3到第6个元素?类似于以下内容。

Dim x(9) as variant, y(3) as variant

    y(0:3) = x(2:5)
sdnqo3pr

sdnqo3pr1#

在VBA中,与Python不同,我们不能直接“子集”数组。
我们只能通过指定ij在某些边界之间来循环索引,例如i在第1行和第2行之间,j在第2列和第3列之间。当然,我们也可以直接通过位置索引数组,例如arr(1)i只是一个表示行索引的变量,j列索引。
或者,我们可以使用Index来“切片”出特定的行或列;我猜你可能会称之为子集,但从你的语法来看,我认为你是在以Python的方式思考。
Application.WorksheetFunction.Index(array,n, 0)将从阵列中分割行n
Application.WorksheetFunction.Index(array, 0, n)将列n从数组中切片出来

Option Explicit

Public Sub ArrayStuff()
    Dim arr(0 To 5) As Long, i As Long
    For i = 0 To 5
        arr(i) = i
    Next

    'Loop only required indices
    For i = 2 To 3
        Debug.Print arr(i)
    Next

    'Slice via Application.WorksheetFunction.Index
    Dim arr2(0 To 2, 0 To 2) As Long, j As Long, counter As Long

    For i = LBound(arr2, 1) To UBound(arr2, 1) '<==  here can specify particular rows
        For j = LBound(arr2, 2) To UBound(arr2, 2) '<== here can specify particular columns
            counter = counter + 1
            arr2(i, j) = counter
        Next
    Next

    MsgBox Join(Application.WorksheetFunction.Transpose(Application.WorksheetFunction.Index(arr2, 0, 1)), ",") 'slice a column out
    MsgBox Join(Application.WorksheetFunction.Index(arr2, 1, 0), ",") 'slice a row out
    MsgBox Join(Application.WorksheetFunction.Index(arr2, 2, 0), ",") 'slice a row out
End Sub
k0pti3hp

k0pti3hp2#

对于任何不想使用循环或范围方法来处理这个问题的人,这里有一个经过测试的解决方案来处理数组的子集(不需要是整行或整列):

Application.Sum(Application.Index(Array(1, 2, 3, 4, 5), 0, Evaluate("ROW(2:5)")))

它将数组的第2个到第5个元素(1,2,3,4,5)求和。对于二维数组,只需执行以下操作:

Application.Average(.Index(DataArray, Evaluate("ROW(17:21)"), 5))

将计算二维数组“DataArray”的五个元素子集(行17到21,列5)的平均值。
顺便说一句,我还没有尝试评估这种方法的效率,但它确实是一种变通方法。希望这能有所帮助。

cxfofazt

cxfofazt3#

Python切片克隆

我最近想要的功能与您在示例中给出的功能相同,它基本上模仿了Python的slice方法-所以我决定编写代码来实现这一点。
请随意阅读我的代码注解,以了解它是如何工作的,但它应该与python的[start:stop:step]相同。
需要注意的是,我写这段代码时确实期望将base设置为0,所以如果你的base不同,代码可能需要首先增强。

' The Slice function takes an input array and returns a new array
' that contains a subset of the elements from the input array.
'
' The subset is defined by the `startIndex`, `stopIndex`, and `stepCount`
' parameters.
'
' The `startIndex` parameter specifies the index of the first
' element to include in the result. If `startIndex` is negative,
' it counts from the end of the input array.
'
' The `stopIndex` parameter specifies the index of the first element
' to exclude from the result. If `stopIndex` is negative, it counts
' from the end of the input array.
'
' The `stepCount` parameter specifies how many elements to skip
' between each element in the result. For example, if `stepCount`
' is 2, every other element will be included in the result. If
' `stepCount` is negative then it works in reverse order.
'
' @author Robert Todar <robert@roberttodar.com>
Public Function Slice( _
    ByVal arr As Variant, _
    Optional ByVal startIndex As Long = 0, _
    Optional ByVal stopIndex As Long = 0, _
    Optional ByVal stepCount As Long = 1 _
) As Variant
    Dim result As Variant
    Dim currentIndex As Long
    Dim resultIndex As Long

    If stepCount = 0 Then
        Err.Raise 5, "Slice", "Step count must be greater than or less than zero."
        Exit Function
    End If

    ' Handle negative indices for startIndex and stopIndex by
    ' converting them to positive indices.
    If startIndex < 0 Then startIndex = UBound(arr) + 1 + startIndex
    If stopIndex < 0 Then stopIndex = UBound(arr) + 1 + stopIndex

    If stepCount > 0 Then
        ' Calculate the stop index if it is not provided (i.e., if it is zero).
        If stopIndex = 0 Then stopIndex = UBound(arr) + 1
        
        ' Calculate the size of the result array based on
        ' start/stop indices and step count.
        resultIndex = (stopIndex - startIndex) \ stepCount - 1
        
        ' Adjust the stopIndex as it is excluded from the results.
        ' This is done after getting the resultIndex as the array
        ' is base 0 and will still need to account for that 0 index.
        stopIndex = stopIndex - 1

    Else
        ' If no input is provided then the start and
        ' stops need to get flipped from the start to
        ' the end.
        If startIndex = 0 Then startIndex = UBound(arr)
        If stopIndex = 0 Then stopIndex = -1

        ' Need to add 1 to the stopindex as it needs to
        ' be excluded from the results. In this senerio,
        ' this is done before the resultIndex is calculated as
        ' we don't have to account for the 0 index.
        stopIndex = stopIndex + 1
        resultIndex = (startIndex - stopIndex) \ Abs(stepCount)
    End If
    
    ' Create a new array with appropriate size to store results.
    ' and get the starting result index. This will be incremented 
    ' each iteration.
    ReDim result(0 To resultIndex)
    resultIndex = LBound(result)

    ' Fill in values for resulting array using start/stop indices
    ' and step count as specified by user inputs.
    For currentIndex = startIndex To stopIndex Step stepCount
        result(resultIndex) = arr(currentIndex)
        resultIndex = resultIndex + 1
    Next currentIndex
    
    ' Return resulting sliced array back to user.
    Slice = result
End Function

演示

下面是一个演示,展示了Python方法与我的版本的比较。

Sub DemoSliceFunction()
    Dim a As Variant
    a = Array(0, 1, 2, 3, 4, 5)

    Debug.Print "Starting Data", Join(a)
    Debug.Print "Python Example: [::]", Join(Slice(a))
    Debug.Print "Python Example: [1:]", Join(Slice(a, 1))
    Debug.Print "Python Example: [-1:]", Join(Slice(a, -1))
    Debug.Print "Python Example: [-2:]", Join(Slice(a, -2))
    Debug.Print "Python Example: [:4]", Join(Slice(a, , 4))
    Debug.Print "Python Example: [1:4]", Join(Slice(a, 1, 4))
    Debug.Print "Python Example: [:-3]", Join(Slice(a, , -3))
    Debug.Print "Python Example: [1:-2]", Join(Slice(a, 1, -2))
    Debug.Print "Python Example: [-3:-2]", Join(Slice(a, -3, -2))
    Debug.Print "Python Example: [::2]", Join(Slice(a, , , 2))
    Debug.Print "Python Example: [::-1]", Join(Slice(a, , , -1))
    Debug.Print "Python Example: [-3::-1]", Join(Slice(a, -3, , -1))
    Debug.Print "Python Example: [-4::-1]", Join(Slice(a, -4, , -1))
    Debug.Print "Python Example: [:-3:-1]", Join(Slice(a, , -3, -1))
    Debug.Print "Python Example: [:-4:-1]", Join(Slice(a, , -4, -1))
    Debug.Print "Python Example: [-2:-5:-1]", Join(Slice(a, -2, -5, -1))
End Sub

测试

此外,我还提供了这个方法的测试脚本。

Sub TestSliceFunction()
    Dim a As Variant
    a = Array(0, 1, 2, 3, 4, 5)

    Debug.Assert Join(a) = "0 1 2 3 4 5"
    Debug.Assert Join(Slice(a)) = "0 1 2 3 4 5"
    Debug.Assert Join(Slice(a, 1)) = "1 2 3 4 5"
    Debug.Assert Join(Slice(a, -1)) = "5"
    Debug.Assert Join(Slice(a, -2)) = "4 5"
    Debug.Assert Join(Slice(a, , 4)) = "0 1 2 3"
    Debug.Assert Join(Slice(a, 1, 4)) = "1 2 3"
    Debug.Assert Join(Slice(a, , -3)) = "0 1 2"
    Debug.Assert Join(Slice(a, 1, -2)) = "1 2 3"
    Debug.Assert Join(Slice(a, -3, -2)) = "3"
    Debug.Assert Join(Slice(a, , , 2)) = "0 2 4"
    Debug.Assert Join(Slice(a, , , -1)) = "5 4 3 2 1 0"
    Debug.Assert Join(Slice(a, -3, , -1)) = "3 2 1 0"
    Debug.Assert Join(Slice(a, -4, , -1)) = "2 1 0"
    Debug.Assert Join(Slice(a, , -3, -1)) = "5 4"
    Debug.Assert Join(Slice(a, , -4, -1)) = "5 4 3"
    Debug.Assert Join(Slice(a, -2, -5, -1)) = "4 3 2"

    Debug.Print "TestSliceFunction: PASS"
End Sub

相关问题