问题
How could I reverse an array that is full of integers e.g.:
[1;5;8;45;54]
To:
[54;45;8;5;1]
Are there any built in functions I could use?
I tried using this method:
Array.Reverse(arr)
I added Mscorlib.dll from Tools > References, but it showed error: Syntax error. At the Array.Reverse(arr) location.
回答1:
Array.Reverse sounds like VB.Net, not VBA.
Chip Pearson has functions for just about anything you will want to do with arrays (and other structures).
http://www.cpearson.com/excel/vbaarrays.htm --> ReverseArrayInPlace
The relevant part is:
Ndx2 = UBound(InputArray)
' loop from the LBound of InputArray to the midpoint of InputArray
For Ndx = LBound(InputArray) To ((UBound(InputArray) - LBound(InputArray) + 1) \ 2)
'swap the elements
Temp = InputArray(Ndx)
InputArray(Ndx) = InputArray(Ndx2)
InputArray(Ndx2) = Temp
' decrement the upper index
Ndx2 = Ndx2 - 1
Next Ndx
回答2:
you could use ArrayList class and wrap its Reverse method:
Function ReverseArray(arr As Variant) As Variant
Dim val As Variant
With CreateObject("System.Collections.ArrayList") '<-- create a "temporary" array list with late binding
For Each val In arr '<--| fill arraylist
.Add val
Next val
.Reverse '<--| reverse it
ReverseArray = .Toarray '<--| write it into an array
End With
End Function
to be used like:
Sub main()
Dim arr As Variant
arr = ReverseArray(Array(1, 2, 3, 4, 5)) '<-- it returns an array of Variant/Integer with values 5,4,3,2,1
End Sub
回答3:
Andre's answer referring to Chip Pearson's function I believe the +1 in the for loop is in error that in cases of LBound and UBound not BOTH being EVEN or BOTH being ODD results in the mid point reversal being reverted. i.e. the difference between LBound and UBound being ODD.
Consider 0 = LBound and 9 = UBound.
9 + 1 = 10 / 2 = 5
So the loop will be for Ndx = 0 to 5. That is 6 iterations. One iteration too many.
Results in the following swaps.
Ndx = 0, Ndx2 = 9: 0<>9
Ndx = 1, Ndx2 = 8: 1<>8
Ndx = 2, Ndx2 = 7: 2<>7
Ndx = 3, Ndx2 = 6: 3<>6
Ndx = 4, Ndx2 = 5: 4<>5
Ndx = 5, Ndx2 = 4: 5<>4
So the mid point elements 4 and 5 are swapped, then swapped back.
Resulting in the order of: 9,8,7,6,4,5,3,2,1,0
Also LBound should be added to the UBound, not subtracted. If subtracted then it only works for LBound of zero. Consider 50 = LBound, 100 = UBound. That would result in For Ndx = 50 to 25. Note, this is supposed to be a FROM, TO calculation not an iterations count calculation.
Here is my functions for reversing one and two dimensional arrays.
They are also able to optionally retain a specified number of header rows.
' Reverse array (one dimensional), optionally retain header rows.
Private Sub Reverse_Array_1d(ByRef Ary As Variant, Optional Header_Rows As Integer = 0)
Dim Dimension_Y As Integer ' Rows (height)
Dim Y_first As Long
Dim Y_last As Long
Dim Y_last_plus_Y_first As Long
Dim Y_next As Long
Dimension_Y = 1
Y_first = LBound(Ary, Dimension_Y) + Header_Rows
Y_last = UBound(Ary, Dimension_Y)
Y_last_plus_Y_first = Y_last + Y_first
Dim tmp As Variant
For Y = Y_first To Y_last_plus_Y_first / 2
Y_next = Y_last_plus_Y_first - Y
tmp = Ary(Y_next)
Ary(Y_next) = Ary(Y)
Ary(Y) = tmp
Next
End Sub
ReDim Ary(0 To 9) As Variant
Header_Rows = 1
Call Reverse_1d_Array(Ary, CInt(Header_Rows))
' Reverse array (two dimensional), optionally retain header rows.
Private Sub Reverse_Array_2d(ByRef Ary As Variant, Optional Header_Rows As Integer = 0)
Dim Dimension_Y As Integer ' Rows (height)
Dim Y_first As Long
Dim Y_last As Long
Dim Y_last_plus_Y_first As Long
Dim Y_next As Long
Dimension_Y = 1
Y_first = LBound(Ary, Dimension_Y) + Header_Rows
Y_last = UBound(Ary, Dimension_Y)
Y_last_plus_Y_first = Y_last + Y_first
Dim Dimension_X As Integer ' Columns (width)
Dim X_first As Long
Dim X_last As Long
Dimension_X = 2
X_first = LBound(Ary, Dimension_X)
X_last = UBound(Ary, Dimension_X)
ReDim tmp(X_first To X_last) As Variant
For Y = Y_first To Y_last_plus_Y_first / 2
Y_next = Y_last_plus_Y_first - Y
For X = X_first To X_last
tmp(X) = Ary(Y_next, X)
Ary(Y_next, X) = Ary(Y, X)
Ary(Y, X) = tmp(X)
Next
Next
End Sub
ReDim Ary(0 To 9, 0 To 3) As Variant
Header_Rows = 1
Call Reverse_2d_Array(Ary, CInt(Header_Rows))
回答4:
(1): The simple but limited solution, if your data is made of of either single characters or palindromes. Let's assume your array is named vTmp, and you can pick a delimiter that doesn't appear in your data -- I'll use "|". Then a one-line approach is:
vTmp = VBA.Split(VBA.StrReverse(VBA.Join(vTmp, "|")), "|")
It is limited, because each value will be reversed as well. It could be solved by replacing the values with indexes that refer to values in another array, but then it's no simpler than the other solutions.
(2): The full solution, as complete Excel VBA function:
Public Function rxReverse(uInput) As Variant
'' Simply reverses the order of items in input array.
'' If Input is singular, then it reverses the content.
''
'' v1 Rich Sulin 05-08-2019
Dim vTmp As Variant
Dim a1 As Long, a2 As Long, a3 As Long
Dim i As Long, j As Long
''
rxReverse = vbNullString
''
'' uInput is a Range object?
If TypeOf uInput Is Range Then
a1 = 1
If uInput.Columns.Count > 1 Then
a2 = uInput.Columns.Count
ReDim vTmp(a1 To a2) As Variant
a3 = 1 + (a2 - a1) / 2
For i = a1 To a3
j = a2 - i + 1
vTmp(j) = uInput(1, i).Value
vTmp(i) = uInput(1, j).Value
Next i
ElseIf uInput.Rows.Count > 1 Then
a2 = uInput.Rows.Count
ReDim vTmp(a1 To a2) As Variant
a3 = 1 + (a2 - a1) / 2
For i = a1 To a3
j = a2 - i + 1
vTmp(j) = uInput(1, i).Value
vTmp(i) = uInput(1, j).Value
Next i
Else
vTmp = VBA.StrReverse(VBA.CStr(uInput.Value))
End If
''
'' uInput is an Array?
Else
Select Case VBA.VarType(uInput)
Case Is >= vbArray
a1 = LBound(uInput)
a2 = UBound(uInput)
ReDim vTmp(a1 To a2) As Variant
a3 = 1 + (a2 - a1) / 2
For i = a1 To a3
j = a2 - i + 1
vTmp(j) = uInput(i)
vTmp(i) = uInput(j)
Next i
''
'' uInput is an irrelevant type?
Case vbNull, vbEmpty, vbError
Exit Function
''
'' uInput is a singular data; reverse it.
Case Else
vTmp = VBA.StrReverse(VBA.CStr(uInput))
End Select
End If
''
rxReverse = vTmp
''
'' If called from a Worksheet, vertically, then orient output array "vertically"
If VBA.IsObject(Application.Caller) Then
If Application.Caller.Rows.Count > 1 Then
rxReverse = Application.WorksheetFunction.Transpose(vTmp)
End If
End If
End Function
来源:https://stackoverflow.com/questions/40563940/vba-reverse-an-array