Visual Basic for Applications/Bubble Sort on Multiple Keys

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Summary[edit | edit source]

Array Sort on Three Keys[edit | edit source]

  • This rather long VBA code listing allows bubble sorting of an array on three keys. It is sometimes called an intersort.
  • In case it is not clear what that means, suppose there are many names to sort; each with two forenames and a surname. The names records occupy a row each and their parts are in separate columns. The first key might sort the surnames column, but there could be many records called Smith. Then the second key sorts among the first forenames where the surnames were similar. And there might still be a lot of John Smith name records that are the same. The third key sorts the second forename column for those cases where there are records with the same surname and first forename combination.
  • A similar function can be found on Excel worksheets in the advanced sort functions. Users unfamiliar with this sort type might well experiment there to better understand the process.
  • The function here has options for ascending or descending sorts, row sort or column sort, and the option to return the sorted work in another array or the original. Up to three keys can be specified, though if there are unused keys, say, because only two intersorts are needed, it is assumed that Key1 and Key2 will be used before Key3. In any case, unreasonable settings will result in message box advice.
Function SortArr2D3Keys(vA As Variant, _
                        Optional Key1 As Long = -1, _
                        Optional Key2 As Long = -1, _
                        Optional Key3 As Long = -1, _
                        Optional ByVal bIsAscending As Boolean = True, _
                        Optional ByVal bIsRowSort As Boolean = True, _
                        Optional ByRef vR As Variant) As Boolean
'--------------------------------------------------------------------------------------
' Procedure : SortArr2D3Keys
' Purpose   : Bubblesorts a 2D array using 3 keys, up or down, on any column or row.
'             For example, sorting using up to three columns;
'             Eg; first sorts surnames, then sorts among same surnames for first names,
'             then among similar surnames with same first names for middle names.
'             Options include in-place, with the source changed, or
'             if supplied, returned in vR, with the source array intact.
'             Optional parameters default to: ROW SORT, ASCENDING.
'             Trailing key options that are not needed should be set to same as previous.
'---------------------------------------------------------------------------------------
    
ASSIGNMENTS:
    Dim condition1 As Boolean, vW As Variant, Temp
    Dim i As Long, j As Long, y As Long, t As Variant
    Dim loR As Long, hiR As Long, loC As Long, hiC As Long
    Dim r As Long, c As Long, bWasMissing As Boolean
    Dim sCombo As String, reply
    Dim b1Used As Boolean, b2Used As Boolean, b3Used As Boolean
    
    'find bounds of vA data input array
    loR = LBound(vA, 1): hiR = UBound(vA, 1)
    loC = LBound(vA, 2): hiC = UBound(vA, 2)
    
    'find whether optional vR was initially missing
    bWasMissing = IsMissing(vR)
    If Not bWasMissing Then Set vR = Nothing
    
KEYCHECKS:
    If Key1 <> -1 Then
        b1Used = True
        'check key within bounds
        If bIsRowSort And (Key1 < loC Or Key1 > hiC) Then
            MsgBox "Sort key1 out of bounds"
            Exit Function
        End If
        If Not bIsRowSort And (Key1 < loR Or Key1 > hiR) Then
            MsgBox "Sort key1 out of bounds"
            Exit Function
        End If
    End If
    
    If Key2 <> -1 Then
        b2Used = True
        'check key within bounds
        If bIsRowSort And (Key2 < loC Or Key2 > hiC) Then
            MsgBox "Sort key2 out of bounds"
            Exit Function
        End If
        If Not bIsRowSort And (Key2 < loR Or Key2 > hiR) Then
            MsgBox "Sort key2 out of bounds"
            Exit Function
        End If
    End If
    
    If Key3 <> -1 Then
        b3Used = True
        'check key within bounds
        If bIsRowSort And (Key3 < loC Or Key3 > hiC) Then
            MsgBox "Sort key3 out of bounds"
            Exit Function
        End If
        If Not bIsRowSort And (Key3 < loR Or Key3 > hiR) Then
            MsgBox "Sort key3 out of bounds"
            Exit Function
        End If
    End If
    
    sCombo = CStr(Abs(b1Used)) & CStr(Abs(b2Used)) & CStr(Abs(b3Used))
    'MsgBox sCombo
    
    Select Case sCombo
    Case "000"
        'no keys selected
        If bIsRowSort Then
           reply = MsgBox("No keys selected." & vbCrLf & _
           "Use lower bound column for a single key?", vbCritical + vbQuestion + vbYesNo, "Please confirm your selection...")
           Select Case reply
           Case vbYes
               Key1 = loC
           Case Else
               Exit Function
           End Select
        Else
           reply = MsgBox("No keys selected." & vbCrLf & _
           "Use lower bound row for a single key?", vbCritical + vbQuestion + vbYesNo, "Please confirm your selection...")
           Select Case reply
           Case vbYes
               Key1 = loR
           Case Else
               Exit Function
           End Select
        End If
    Case "100", "110", "111"
        'proceed normally
    Case Else
        MsgBox "Only three combinations of sort keys are possible" & vbCrLf & _
        "Key1 alone, Key1 with Key2, or Key1 with Key2 and Key3."
        Exit Function
    End Select
    
WORKARRAY:
    'use a working array for sorting
    vW = vA
    
STEERING:
    'steer input options
    If bIsRowSort Then GoTo ROWSORT Else GoTo COLSORT
    
ROWSORT:
    'row sort using 3 intersort keys
    'Sort rows of array using first column index, Key1
    For i = loR To hiR - 1
        For j = i + 1 To hiR
            'set < for descending, and > for ascending
            If bIsAscending Then
                condition1 = vW(i, Key1) > vW(j, Key1)
            Else
                condition1 = vW(i, Key1) < vW(j, Key1)
            End If
            If condition1 Then
                For c = loC To hiC
                    Temp = vW(i, c)
                    vW(i, c) = vW(j, c)
                    vW(j, c) = Temp
                Next
            End If
        Next
    Next
    If b2Used Then
        'Sort rows of array using second column index, Key2
        For i = loR To hiR - 1
            For j = i + 1 To hiR
                'if-condition avoids independence of second sort
                'note that a third stage would have THREE terms
                If vW(i, Key1) = vW(j, Key1) Then
                    'set < for descending, and > for ascending
                    If bIsAscending Then
                        condition1 = vW(i, Key2) > vW(j, Key2)
                    Else
                        condition1 = vW(i, Key2) < vW(j, Key2)
                    End If
                    If condition1 Then
                        For c = loC To hiC
                            Temp = vW(i, c)
                            vW(i, c) = vW(j, c)
                            vW(j, c) = Temp
                        Next
                    End If
                End If
            Next
        Next
    Else
        GoTo TRANSFERS
    End If
    If b3Used Then
        'Sort rows of array using third column index, Key3
        For i = loR To hiR - 1
            For j = i + 1 To hiR
                'if-condition avoids independence of second sort
                'note that a third stage would have THREE terms
                If vW(i, Key1) = vW(j, Key1) And vW(i, Key2) = vW(j, Key2) Then
                    'set < for descending, and > for ascending
                    If bIsAscending Then
                        condition1 = vW(i, Key3) > vW(j, Key3)
                    Else
                        condition1 = vW(i, Key3) < vW(j, Key3)
                    End If
                    If condition1 Then
                        For c = loC To hiC
                            Temp = vW(i, c)
                            vW(i, c) = vW(j, c)
                            vW(j, c) = Temp
                        Next
                    End If
                End If
            Next
        Next
    End If
    GoTo TRANSFERS
   
COLSORT:
    'column sort using 3 intersort keys
    'Sort columns of array using first row index, Key1
    For i = loC To hiC - 1
        For j = i + 1 To hiC
            'set < for descending, and > for ascending
            If bIsAscending Then
                condition1 = vW(Key1, i) > vW(Key1, j)
            Else
                condition1 = vW(Key1, i) < vW(Key1, j)
            End If
            If condition1 Then
                For c = loR To hiR
                    Temp = vW(c, i)
                    vW(c, i) = vW(c, j)
                    vW(c, j) = Temp
                Next
            End If
        Next
    Next
    If b2Used Then
        'Sort columns of array using second row index, Key2
        For i = loC To hiC - 1
            For j = i + 1 To hiC
                'if-condition avoids independence of second sort
                'note that a third stage would have THREE terms
                If vW(Key1, i) = vW(Key1, j) Then
                    'set < for descending, and > for ascending
                    If bIsAscending Then
                        condition1 = vW(Key2, i) > vW(Key2, j)
                    Else
                        condition1 = vW(Key2, i) < vW(Key2, j)
                    End If
                    If condition1 Then
                        For c = loR To hiR
                            Temp = vW(c, i)
                            vW(c, i) = vW(c, j)
                            vW(c, j) = Temp
                        Next
                    End If
                End If
            Next
        Next
    Else
        GoTo TRANSFERS
    End If
    If b3Used Then
        'Sort columns of array using third  row index, Key2
        For i = loC To hiC - 1
            For j = i + 1 To hiC
                'if-condition avoids independence of second sort
                'note that a third stage would have THREE terms
                If vW(Key1, i) = vW(Key1, j) And vW(Key2, i) = vW(Key2, j) Then
                    'set < for descending, and > for ascending
                    If bIsAscending Then
                        condition1 = vW(Key3, i) > vW(Key3, j)
                    Else
                        condition1 = vW(Key3, i) < vW(Key3, j)
                    End If
                    If condition1 Then
                        For c = loR To hiR
                            Temp = vW(c, i)
                            vW(c, i) = vW(c, j)
                            vW(c, j) = Temp
                        Next
                    End If
                End If
            Next
        Next
    End If
    GoTo TRANSFERS
    
TRANSFERS:
    'decide whether to return in vA or vR
    If Not bWasMissing Then
        'vR was the intended return array
        'so return vR leaving vA intact
        vR = vW
    Else:
        'vR is not intended
        'so reload vA with vR
        vA = vW
    End If
    
    'set return function value
    SortArr2D3Keys = True
    
End Function