如何在 excel vba 中获取数组中的第 3 到第 6 个元素?像下面这样的东西。
Dim x(9) as variant, y(3) as variant
y(0:3) = x(2:5)
在 VBA 中,不像在 python 中,我们不能直接“子集化”一个数组。
我们只能通过指定
i
和 j
在某些边界之间来循环感兴趣的索引,例如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
对于不想使用循环或范围方法处理此问题的任何人, 这是一个经过测试的解决方案,用于处理数组的子集(不需要是整行或整列):
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 列)的平均值。
顺便说一句,我还没有尝试评估这种方法的效率,但它确实是一种解决方法。希望这会有所帮助。
我最近想要您在示例中提供的相同功能,它基本上模仿了 Python 的 slice 方法——所以我决定编写代码来做到这一点。
随意阅读我的代码注释以了解其工作原理,但它应该与 pythons
[start:stop:step]
格式相同。
请注意,我写这篇文章时希望将基数设置为 0,因此如果您的基数不同,则可能需要先增强代码。
' 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 <[email protected]>
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