如果我理解正确,您需要的是索引排序。许多语言提供索引排序作为标准功能。 VBA 既没有标准排序也没有索引排序。
使用传统的数组排序,值在数组中进行排序。例如:假设我有一个包含值的数组:
A D B E C
如果我将该数组传递给排序,则返回为:
A B C D E
但有时您无法对数组进行排序。在您的情况下,该数组是一系列列标题。您无法对这些标题进行排序,因为它们属于它们的列。您将不得不对列进行排序,这充其量是不切实际的,而且可能是不可接受的,因为列的顺序将意味着什么。
使用索引排序,您可以创建数组键和索引:
Keys A D B E C
Indices 1 2 3 4 5
这两个数组都被传递给排序,保持键不变并对索引进行排序以给出:
Indices 1 3 5 2 4
使用常规排序,您可以以Array(1) 访问已排序的条目。 Array(2) 等等。使用索引排序,您可以以Array(Indices(1)) 访问已排序的条目。 Array(Indices(2)) 等等。
通过索引获取排序的条目起初可能有点难以理解,而且直接访问源数组无疑更复杂。
下面我给你一个索引插入排序。插入排序简单易懂,但条目数大时速度较慢。您只有五个条目要排序,因此它的性能是可以接受的。查看“插入排序”的 Wiki 条目,了解其工作原理。
宏DemoSortColumnHeadings 显示如何使用排序以及如何访问列标题。我使用名称ColHeads 而不是Keys 和ColNums 而不是Indices,因为我相信这将使DemoSortColumnHeadings 更容易理解。排序后的ColNums 包含您需要的序列中的列号。排序后,数组ColHeads就不再需要了。
最后一点。 VBA 是我所知道的唯一一种允许您指定数组的下限和上限的语言。大多数语言要求下限为零。我利用这一点将数组的维度定义为(2 到 6)而不是(0 到 4)。这就是为什么数组ColNums 中的值是列号的原因。对于大多数语言,我需要 ColNums(N)+2 来获取列号。
Option Explicit
Sub DemoSortColumnHeadings()
Const ColFirst As Long = 2 ' Column B = column 2
Const ColLast As Long = 6 ' Column F = column 6
Dim ColCrnt As Long
Dim ColNums() As Long
Dim InxColNum As Long
Dim ColHeads() As String
With Worksheets("Test data")
ReDim ColHeads(ColFirst To ColLast)
ReDim ColNums(ColFirst To ColLast)
For ColCrnt = ColFirst To ColLast
ColHeads(ColCrnt) = .Cells(1, ColCrnt).Value
ColNums(ColCrnt) = ColCrnt
Next
Debug.Print "Initial sequence"
Debug.Print "|";
For ColCrnt = ColFirst To ColLast
Debug.Print .Cells(1, ColCrnt).Value & "|";
Next
Debug.Print
Call InsertionSort(ColNums, ColHeads)
Debug.Print "Final sequence"
Debug.Print "|";
For InxColNum = LBound(ColNums) To UBound(ColNums)
ColCrnt = ColNums(InxColNum)
Debug.Print .Cells(1, ColCrnt).Value & "|";
Next
Debug.Print
End With
End Sub
Public Sub InsertionSort(ByRef Indices() As Long, ByRef Keys() As String)
Dim Found As Boolean
Dim I As Long
Dim InxIFwd As Long
Dim InxIBack As Long
For InxIFwd = LBound(Indices) + 1 To UBound(Indices)
I = Indices(InxIFwd) ' Save value of current entry in Indices
' Find first entry back, if any, such that Keys(I) >= Keys(Indices(InxIBack))
' If Keys(I) < Keys(Indices(InxIBack)), set Indices(InxIBack+1) to
' Indices(InxIBack). That is move indices for keys greater that Keys(I) down
' Indices leaving a space for I nearer the beginning.
Found = False
For InxIBack = InxIFwd - 1 To LBound(Indices) Step -1
If Keys(I) >= Keys(Indices(InxIBack)) Then
' Keys(I) belongs after Keys(Indices(InxIBack))
Indices(InxIBack + 1) = I
Found = True
Exit For
End If
Indices(InxIBack + 1) = Indices(InxIBack)
Next
If Not Found Then
' Insertion point for I not found so it belongs at beginning of Indices
Indices(LBound(Indices)) = I
End If
Next
End Sub