Функція сортування масиву VBA?


83

Я шукаю гідну реалізацію сортування для масивів у VBA. Кращим буде швидкий сорт. Або достатньо будь-якого іншого алгоритму сортування, крім міхура або злиття.

Зверніть увагу, що це працює для роботи з MS Project 2003, тому слід уникати будь-яких власних функцій Excel та будь-чого, пов’язаного з .net.


3
Може бути цікаво подивитися тут: rosettacode.org/wiki/Sorting_algorithms/Quicksort#VBA
MjrKusanagi

Чому вам не подобається сортувати злиття?
jwg

Відповіді:


101

Погляньте тут :
Редагувати: З тих пір джерело, на яке посилається (allexperts.com), закрито, але ось відповідні коментарі автора :

В Інтернеті доступно багато алгоритмів для сортування. Найбільш універсальним і, як правило, найшвидшим є алгоритм Quicksort . Нижче наведена функція для нього.

Зателефонуйте йому, просто передавши масив значень (рядок або числовий; це не має значення) з нижньою межею масиву (зазвичай 0) та верхньою межею масиву (тобто UBound(myArray).)

Приклад :Call QuickSort(myArray, 0, UBound(myArray))

Коли це буде зроблено, myArrayбуде відсортовано, і ви зможете робити з ним, що хочете.
(Джерело: archive.org )

Public Sub QuickSort(vArray As Variant, inLow As Long, inHi As Long)
  Dim pivot   As Variant
  Dim tmpSwap As Variant
  Dim tmpLow  As Long
  Dim tmpHi   As Long

  tmpLow = inLow
  tmpHi = inHi

  pivot = vArray((inLow + inHi) \ 2)

  While (tmpLow <= tmpHi)
     While (vArray(tmpLow) < pivot And tmpLow < inHi)
        tmpLow = tmpLow + 1
     Wend

     While (pivot < vArray(tmpHi) And tmpHi > inLow)
        tmpHi = tmpHi - 1
     Wend

     If (tmpLow <= tmpHi) Then
        tmpSwap = vArray(tmpLow)
        vArray(tmpLow) = vArray(tmpHi)
        vArray(tmpHi) = tmpSwap
        tmpLow = tmpLow + 1
        tmpHi = tmpHi - 1
     End If
  Wend

  If (inLow < tmpHi) Then QuickSort vArray, inLow, tmpHi
  If (tmpLow < inHi) Then QuickSort vArray, tmpLow, inHi
End Sub

Зверніть увагу, що це працює лише з одновимірними (відомими як "звичайні"?) Масиви. (Там же робочий багатовимірний масив QuickSort тут .)


2
Це трохи швидша реалізація при роботі з дублікатами. Можливо, завдяки \ 2. Хороша відповідь :)
Марк Нолд

Велике спасибі за це! Я використовував сортування вставки для набору даних 2500 записів, і для правильної сортування знадобилося б близько 22 секунд. Тепер це робиться за секунду, це диво! ;)
djule5

Ефект від цієї функції, здається, завжди переміщує перший елемент з джерела в останню позицію в пункті призначення та відсортує решту масиву.
Жасмин

Все ще приємне рішення через 9 років тому. Але, на жаль, посилання на сторінку allexperts.com більше не існує ...
Egalth

2
@Egalth - Я оновив запитання інформацією, яка була в першоджерелі
ashleedawg

16

Я перетворив алгоритм швидкого швидкого сортування на VBA, якщо хтось інший цього хоче.

Я оптимізував його для роботи з масивом Int / Longs, але перетворити його в той, який працює на довільних порівнянних елементах, має бути просто.

Private Sub QuickSort(ByRef a() As Long, ByVal l As Long, ByVal r As Long)
    Dim M As Long, i As Long, j As Long, v As Long
    M = 4

    If ((r - l) > M) Then
        i = (r + l) / 2
        If (a(l) > a(i)) Then swap a, l, i '// Tri-Median Methode!'
        If (a(l) > a(r)) Then swap a, l, r
        If (a(i) > a(r)) Then swap a, i, r

        j = r - 1
        swap a, i, j
        i = l
        v = a(j)
        Do
            Do: i = i + 1: Loop While (a(i) < v)
            Do: j = j - 1: Loop While (a(j) > v)
            If (j < i) Then Exit Do
            swap a, i, j
        Loop
        swap a, i, r - 1
        QuickSort a, l, j
        QuickSort a, i + 1, r
    End If
End Sub

Private Sub swap(ByRef a() As Long, ByVal i As Long, ByVal j As Long)
    Dim T As Long
    T = a(i)
    a(i) = a(j)
    a(j) = T
End Sub

Private Sub InsertionSort(ByRef a(), ByVal lo0 As Long, ByVal hi0 As Long)
    Dim i As Long, j As Long, v As Long

    For i = lo0 + 1 To hi0
        v = a(i)
        j = i
        Do While j > lo0
            If Not a(j - 1) > v Then Exit Do
            a(j) = a(j - 1)
            j = j - 1
        Loop
        a(j) = v
    Next i
End Sub

Public Sub sort(ByRef a() As Long)
    QuickSort a, LBound(a), UBound(a)
    InsertionSort a, LBound(a), UBound(a)
End Sub

Це були коментарі до алгоритму, до речі: автор Джеймс Гослінг та Кевін А. Сміт розширили TriMedian та InsertionSort Дениса Аренса, з усіма порадами Роберта Седжвіка, він використовує TriMedian та InsertionSort для списків, менших за 4. Це загальна версія алгоритму швидкого сортування CAR Hoare. Це буде обробляти вже відсортовані масиви та масиви з повторюваними ключами.
Ален

17
Слава богу, я це опублікував. Через 3 години я зазнав аварії і втратив робочий день, але принаймні можу це відновити. Тепер це Карма на роботі. Комп’ютери важкі.
Ален

11

Пояснення німецькою мовою, але код є добре перевіреною реалізацією на місці:

Private Sub QuickSort(ByRef Field() As String, ByVal LB As Long, ByVal UB As Long)
    Dim P1 As Long, P2 As Long, Ref As String, TEMP As String

    P1 = LB
    P2 = UB
    Ref = Field((P1 + P2) / 2)

    Do
        Do While (Field(P1) < Ref)
            P1 = P1 + 1
        Loop

        Do While (Field(P2) > Ref)
            P2 = P2 - 1
        Loop

        If P1 <= P2 Then
            TEMP = Field(P1)
            Field(P1) = Field(P2)
            Field(P2) = TEMP

            P1 = P1 + 1
            P2 = P2 - 1
        End If
    Loop Until (P1 > P2)

    If LB < P2 Then Call QuickSort(Field, LB, P2)
    If P1 < UB Then Call QuickSort(Field, P1, UB)
End Sub

Викликається так:

Call QuickSort(MyArray, LBound(MyArray), UBound(MyArray))

1
Я отримую помилку для поля ByVal () і повинен використовувати стандартний ByRef.
Mark Nold

@MarkNold - я теж
Річард Х

це все одно byref, тому що byval не дозволяв би змінювати + зберігати значення поля. Якщо вам абсолютно потрібен byval у переданому аргументі, використовуйте варіант замість рядка та без дужок ().
Патрік Лепелтьє

@Patrick Так, я насправді не здогадуюсь, як там ByValпотрапило. Плутанина, мабуть, виникла через те, що у VB.NET ByValтут буде працювати (хоча це все одно буде реалізовано у VB.NET).
Конрад Рудольф

9
Dim arr As Object
Dim InputArray

'Creating a array list
Set arr = CreateObject("System.Collections.ArrayList")

'String
InputArray = Array("d", "c", "b", "a", "f", "e", "g")

'number
'InputArray = Array(6, 5, 3, 4, 2, 1)

' adding the elements in the array to array_list
For Each element In InputArray
    arr.Add element
Next

'sorting happens
arr.Sort

'Converting ArrayList to an array
'so now a sorted array of elements is stored in the array sorted_array.

sorted_array = arr.toarray

Чи можете ви перетворити це на функцію і показати приклад виводу? Будь-які ідеї щодо швидкості?
not2qubit

2
@Ans відхилили ваше редагування - ви видалили всі коментарі до конверсії, тому залишився лише не коментований код (як функція). Короткість є приємною, але не при зменшенні "зрозумілості" для інших читачів цього звіту.
Патрік Артнер,

@Patrick Artner Код дуже простий, особливо в порівнянні з іншими прикладами, розміщеними тут. Я думаю, що якби хтось шукав тут найпростіший приклад, він міг би знайти його швидше, якби залишився лише відповідний код.
Відповідь

Це була б чудова відповідь, але вам, мабуть, доведеться вирішити проблему, яка System.Collections.ArrayListзнаходиться в різних місцях 32-бітної та 64-бітної Windows. Мій 32-бітний Excel неявно намагається знайти його там, де його зберігав би 32-бітний Win, але оскільки у мене 64-бітний Win, у мене також є проблема: / Я отримую повідомлення про помилку -2146232576 (80131700).
ZygD

Дякую Prasand! Розумна альтернатива іншим підходам грубої сили.
пстратон

7

Натуральне число (рядки) Швидке сортування

Просто щоб нагромадити тему. Зазвичай, якщо ви відсортуєте рядки з числами, ви отримаєте щось подібне:

    Text1
    Text10
    Text100
    Text11
    Text2
    Text20

Але ви дійсно хочете, щоб воно розпізнавало числові значення і було сортується як

    Text1
    Text2
    Text10
    Text11
    Text20
    Text100

Ось як це зробити ...

Примітка:

  • Я давно вкрав швидке сортування з Інтернету, не знаючи, де зараз ...
  • Я переклав функцію CompareNaturalNum, яка спочатку була написана на мові C, також з Інтернету.
  • Відмінність від інших Q-сортів: я не поміняю місцями значення, якщо BottomTemp = TopTemp

Швидке сортування натурального числа

Public Sub QuickSortNaturalNum(strArray() As String, intBottom As Integer, intTop As Integer)
Dim strPivot As String, strTemp As String
Dim intBottomTemp As Integer, intTopTemp As Integer

    intBottomTemp = intBottom
    intTopTemp = intTop

    strPivot = strArray((intBottom + intTop) \ 2)

    Do While (intBottomTemp <= intTopTemp)
        ' < comparison of the values is a descending sort
        Do While (CompareNaturalNum(strArray(intBottomTemp), strPivot) < 0 And intBottomTemp < intTop)
            intBottomTemp = intBottomTemp + 1
        Loop
        Do While (CompareNaturalNum(strPivot, strArray(intTopTemp)) < 0 And intTopTemp > intBottom) '
            intTopTemp = intTopTemp - 1
        Loop
        If intBottomTemp < intTopTemp Then
            strTemp = strArray(intBottomTemp)
            strArray(intBottomTemp) = strArray(intTopTemp)
            strArray(intTopTemp) = strTemp
        End If
        If intBottomTemp <= intTopTemp Then
            intBottomTemp = intBottomTemp + 1
            intTopTemp = intTopTemp - 1
        End If
    Loop

    'the function calls itself until everything is in good order
    If (intBottom < intTopTemp) Then QuickSortNaturalNum strArray, intBottom, intTopTemp
    If (intBottomTemp < intTop) Then QuickSortNaturalNum strArray, intBottomTemp, intTop
End Sub

Порівняння натуральних чисел (використовується для швидкого сортування)

Function CompareNaturalNum(string1 As Variant, string2 As Variant) As Integer
'string1 is less than string2 -1
'string1 is equal to string2 0
'string1 is greater than string2 1
Dim n1 As Long, n2 As Long
Dim iPosOrig1 As Integer, iPosOrig2 As Integer
Dim iPos1 As Integer, iPos2 As Integer
Dim nOffset1 As Integer, nOffset2 As Integer

    If Not (IsNull(string1) Or IsNull(string2)) Then
        iPos1 = 1
        iPos2 = 1
        Do While iPos1 <= Len(string1)
            If iPos2 > Len(string2) Then
                CompareNaturalNum = 1
                Exit Function
            End If
            If isDigit(string1, iPos1) Then
                If Not isDigit(string2, iPos2) Then
                    CompareNaturalNum = -1
                    Exit Function
                End If
                iPosOrig1 = iPos1
                iPosOrig2 = iPos2
                Do While isDigit(string1, iPos1)
                    iPos1 = iPos1 + 1
                Loop

                Do While isDigit(string2, iPos2)
                    iPos2 = iPos2 + 1
                Loop

                nOffset1 = (iPos1 - iPosOrig1)
                nOffset2 = (iPos2 - iPosOrig2)

                n1 = Val(Mid(string1, iPosOrig1, nOffset1))
                n2 = Val(Mid(string2, iPosOrig2, nOffset2))

                If (n1 < n2) Then
                    CompareNaturalNum = -1
                    Exit Function
                ElseIf (n1 > n2) Then
                    CompareNaturalNum = 1
                    Exit Function
                End If

                ' front padded zeros (put 01 before 1)
                If (n1 = n2) Then
                    If (nOffset1 > nOffset2) Then
                        CompareNaturalNum = -1
                        Exit Function
                    ElseIf (nOffset1 < nOffset2) Then
                        CompareNaturalNum = 1
                        Exit Function
                    End If
                End If
            ElseIf isDigit(string2, iPos2) Then
                CompareNaturalNum = 1
                Exit Function
            Else
                If (Mid(string1, iPos1, 1) < Mid(string2, iPos2, 1)) Then
                    CompareNaturalNum = -1
                    Exit Function
                ElseIf (Mid(string1, iPos1, 1) > Mid(string2, iPos2, 1)) Then
                    CompareNaturalNum = 1
                    Exit Function
                End If

                iPos1 = iPos1 + 1
                iPos2 = iPos2 + 1
            End If
        Loop
        ' Everything was the same so far, check if Len(string2) > Len(String1)
        ' If so, then string1 < string2
        If Len(string2) > Len(string1) Then
            CompareNaturalNum = -1
            Exit Function
        End If
    Else
        If IsNull(string1) And Not IsNull(string2) Then
            CompareNaturalNum = -1
            Exit Function
        ElseIf IsNull(string1) And IsNull(string2) Then
            CompareNaturalNum = 0
            Exit Function
        ElseIf Not IsNull(string1) And IsNull(string2) Then
            CompareNaturalNum = 1
            Exit Function
        End If
    End If
End Function

isDigit (використовується у CompareNaturalNum)

Function isDigit(ByVal str As String, pos As Integer) As Boolean
Dim iCode As Integer
    If pos <= Len(str) Then
        iCode = Asc(Mid(str, pos, 1))
        If iCode >= 48 And iCode <= 57 Then isDigit = True
    End If
End Function

Приємно - мені подобається сорт NaturalNumber - доведеться додати це як опцію
Марк Нольд

6

Я опублікував якийсь код у відповідь на відповідне питання на StackOverflow:

Сортування багатовимірного масиву у VBA

Зразки коду в цьому потоці включають:

  1. Векторний масив Quicksort;
  2. Багатостовпковий масив QuickSort;
  3. BubbleSort.

Оптимізований Ален Quicksort дуже блискучий: я щойно зробив базове розділення та повторне повторення, але наведений вище зразок коду має функцію 'gating', яка зменшує надмірне порівняння повторюваних значень. З іншого боку, я кодую Excel, і в захисному кодуванні є дещо більше - будьте застережені, воно вам знадобиться, якщо ваш масив містить згубний варіант 'Empty ()', який зламає ваш While .. Витратьте оператори порівняння і захопіть ваш код у нескінченний цикл.

Зауважте, що алгоритми швидкого сортування - і будь-який рекурсивний алгоритм - можуть заповнити стек і розбити Excel. Якщо у вашому масиві менше 1024 членів, я б використав елементарний BubbleSort.

Public Sub QuickSortArray (ByRef SortArray як варіант, _
                                Необов’язково lngMin Довгий = -1, _ 
                                Необов’язково lngMax As Long = -1, _ 
                                Необов’язково lngColumn As Long = 0)
On Error Resume Next 
'Сортувати двовимірний масив
'Зразок використання: сортуйте arrData за вмістом стовпця 3 ' 'QuickSortArray arrData,,, 3
' "Опублікував Джим Рех, 20.10.98, Excel. Програмування
" Модифікації, Найджел Хеффернан:
'' Помилка втечі порівняння з порожнім варіантом '' Захисне кодування: перевірте вводи
Dim i As Long Dim j As Long Затемнити varMid як варіант Невиразний arrRowTemp як варіант Вимкнути lngColTemp як довго

Якщо IsEmpty (SortArray) Тоді Вийти з під Завершити якщо
Якщо InStr (TypeName (SortArray), "()") <1 Тоді 'IsArray () дещо зламаний: Шукайте дужки в назві типу Вийти з під Завершити якщо
Якщо lngMin = -1 Тоді lngMin = LBound (SortArray, 1) Завершити якщо
Якщо lngMax = -1 Тоді lngMax = UBound (SortArray, 1) Завершити якщо
Якщо lngMin> = lngMax Тоді сортування не потрібно Вийти з під Завершити якщо

i = lngMin j = lngMax
varMid = Порожній varMid = SortArray ((lngMin + lngMax) \ 2, lngColumn)
"Ми надсилаємо" Порожні "та недійсні елементи даних у кінець списку: If IsObject (varMid) Тоді 'зверніть увагу, що ми не перевіряємо isObject (SortArray (n)) - varMid може вибрати дійсний член або властивість за замовчуванням i = lngMax j = lngMin ElseIf IsEmpty (varMid) Тоді i = lngMax j = lngMin ElseIf IsNull (varMid) Тоді i = lngMax j = lngMin ElseIf varMid = "" Тоді i = lngMax j = lngMin ElseIf varType (varMid) = vbError Тоді i = lngMax j = lngMin ElseIf varType (varMid)> 17 Тоді i = lngMax j = lngMin Кінець, якщо в

той час як i <= j
Тоді як SortArray (i, lngColumn) <varMid І i <lngMax i = i + 1 Венд
Тоді як varMid <SortArray (j, lngColumn) And j> lngMin j = j - 1 Wend

Якщо i <= j Тоді
'Поміняти місцями рядки ReDim arrRowTemp (LBound (SortArray, 2) To UBound (SortArray, 2)) Для lngColTemp = LBound (SortArray, 2) To UBound (SortArray, 2) arrRowTemp (lngColTemp) = SortArray (i, lngColTemp) SortArray (i, lngColTemp) = SortArray (j, lngColTemp) SortArray (j, lngColTemp) = arrRowTemp (lngColTemp) Далі lngColTemp Стерти arrRowTemp
i = i + 1 j = j - 1
Кінець, якщо

Wend
Якщо (lngMin <j) Тоді викличте QuickSortArray (SortArray, lngMin, j, lngColumn) Якщо (i <lngMax), то викличте QuickSortArray (SortArray, i, lngMax, lngColumn)

End Sub


2

Ви не хотіли рішення на основі Excel, але оскільки у мене сьогодні була та сама проблема, і я хотів протестувати за допомогою інших функцій програм Office, я написав функцію нижче.

Обмеження:

  • 2-мірні масиви;
  • максимум 3 стовпці як ключі сортування;
  • залежить від Excel;

Перевірено виклик Excel 2010 із Visio 2010


Option Base 1


Private Function sort_array_2D_excel(array_2D, array_sortkeys, Optional array_sortorders, Optional tag_header As String = "Guess", Optional tag_matchcase As String = "False")

'   Dependencies: Excel; Tools > References > Microsoft Excel [Version] Object Library

    Dim excel_application As Excel.Application
    Dim excel_workbook As Excel.Workbook
    Dim excel_worksheet As Excel.Worksheet

    Set excel_application = CreateObject("Excel.Application")

    excel_application.Visible = True
    excel_application.ScreenUpdating = False
    excel_application.WindowState = xlNormal

    Set excel_workbook = excel_application.Workbooks.Add
    excel_workbook.Activate

    Set excel_worksheet = excel_workbook.Worksheets.Add
    excel_worksheet.Activate
    excel_worksheet.Visible = xlSheetVisible

    Dim excel_range As Excel.Range
    Set excel_range = excel_worksheet.Range("A1").Resize(UBound(array_2D, 1) - LBound(array_2D, 1) + 1, UBound(array_2D, 2) - LBound(array_2D, 2) + 1)
    excel_range = array_2D


    For i_sortkey = LBound(array_sortkeys) To UBound(array_sortkeys)

        If IsNumeric(array_sortkeys(i_sortkey)) Then
            sortkey_range = Chr(array_sortkeys(i_sortkey) + 65 - 1) & "1"
            Set array_sortkeys(i_sortkey) = excel_worksheet.Range(sortkey_range)

        Else
            MsgBox "Error in sortkey parameter:" & vbLf & "array_sortkeys(" & i_sortkey & ") = " & array_sortkeys(i_sortkey) & vbLf & "Terminating..."
            End

        End If

    Next i_sortkey


    For i_sortorder = LBound(array_sortorders) To UBound(array_sortorders)
        Select Case LCase(array_sortorders(i_sortorder))
            Case "asc"
                array_sortorders(i_sortorder) = XlSortOrder.xlAscending
            Case "desc"
                array_sortorders(i_sortorder) = XlSortOrder.xlDescending
            Case Else
                array_sortorders(i_sortorder) = XlSortOrder.xlAscending
        End Select
    Next i_sortorder

    Select Case LCase(tag_header)
        Case "yes"
            tag_header = Excel.xlYes
        Case "no"
            tag_header = Excel.xlNo
        Case "guess"
            tag_header = Excel.xlGuess
        Case Else
            tag_header = Excel.xlGuess
    End Select

    Select Case LCase(tag_matchcase)
        Case "true"
            tag_matchcase = True
        Case "false"
            tag_matchcase = False
        Case Else
            tag_matchcase = False
    End Select


    Select Case (UBound(array_sortkeys) - LBound(array_sortkeys) + 1)
        Case 1
            Call excel_range.Sort(Key1:=array_sortkeys(1), Order1:=array_sortorders(1), Header:=tag_header, MatchCase:=tag_matchcase)
        Case 2
            Call excel_range.Sort(Key1:=array_sortkeys(1), Order1:=array_sortorders(1), Key2:=array_sortkeys(2), Order2:=array_sortorders(2), Header:=tag_header, MatchCase:=tag_matchcase)
        Case 3
            Call excel_range.Sort(Key1:=array_sortkeys(1), Order1:=array_sortorders(1), Key2:=array_sortkeys(2), Order2:=array_sortorders(2), Key3:=array_sortkeys(3), Order3:=array_sortorders(3), Header:=tag_header, MatchCase:=tag_matchcase)
        Case Else
            MsgBox "Error in sortkey parameter:" & vbLf & "Maximum number of sort columns is 3!" & vbLf & "Currently passed: " & (UBound(array_sortkeys) - LBound(array_sortkeys) + 1)
            End
    End Select


    For i_row = 1 To excel_range.Rows.Count

        For i_column = 1 To excel_range.Columns.Count

            array_2D(i_row, i_column) = excel_range(i_row, i_column)

        Next i_column

    Next i_row


    excel_workbook.Close False
    excel_application.Quit

    Set excel_worksheet = Nothing
    Set excel_workbook = Nothing
    Set excel_application = Nothing


    sort_array_2D_excel = array_2D


End Function

Це приклад того, як перевірити функцію:

Private Sub test_sort()

    array_unsorted = dim_sort_array()

    Call msgbox_array(array_unsorted)

    array_sorted = sort_array_2D_excel(array_unsorted, Array(2, 1, 3), Array("desc", "", "asdas"), "yes", "False")

    Call msgbox_array(array_sorted)

End Sub


Private Function dim_sort_array()

    Dim array_unsorted(1 To 5, 1 To 3) As String

    i_row = 0

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "Column1": array_unsorted(i_row, 2) = "Column2": array_unsorted(i_row, 3) = "Column3"

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "OR": array_unsorted(i_row, 2) = "A": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "XOR": array_unsorted(i_row, 2) = "A": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "NOT": array_unsorted(i_row, 2) = "B": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "AND": array_unsorted(i_row, 2) = "A": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    dim_sort_array = array_unsorted

End Function


Sub msgbox_array(array_2D, Optional string_info As String = "2D array content:")

    msgbox_string = string_info & vbLf

    For i_row = LBound(array_2D, 1) To UBound(array_2D, 1)

        msgbox_string = msgbox_string & vbLf & i_row & vbTab

        For i_column = LBound(array_2D, 2) To UBound(array_2D, 2)

            msgbox_string = msgbox_string & array_2D(i_row, i_column) & vbTab

        Next i_column

    Next i_row

    MsgBox msgbox_string

End Sub

Якщо хтось тестує це за допомогою інших версій Office, будь ласка, напишіть тут, якщо виникнуть проблеми.


1
Я забув згадати, що msgbox_array()це функція, яка корисна для швидкого перевірки будь-якого двовимірного масиву під час налагодження.
lucas0x7B

1

Цікаво, що б ви сказали про цей код сортування масиву. Це швидко для впровадження і робить свою роботу ... ще не тестував великі масиви. Він працює для одновимірних масивів, для багатовимірних додаткових значень потрібно буде побудувати матрицю для переміщення (з розміром менше, ніж початковий масив).

       For AR1 = LBound(eArray, 1) To UBound(eArray, 1)
            eValue = eArray(AR1)
            For AR2 = LBound(eArray, 1) To UBound(eArray, 1)
                If eArray(AR2) < eValue Then
                    eArray(AR1) = eArray(AR2)
                    eArray(AR2) = eValue
                    eValue = eArray(AR1)
                End If
            Next AR2
        Next AR1

5
Це сортування бульбашок. ОП попросив щось інше, ніж міхур.
Michiel van der Blonk

0

Я думаю, що мій код (протестований) є більш "освіченим", припускаючи, що простіший - краще .

Option Base 1

'Function to sort an array decscending
Function SORT(Rango As Range) As Variant
    Dim check As Boolean
    check = True
    If IsNull(Rango) Then
        check = False
    End If
    If check Then
        Application.Volatile
        Dim x() As Variant, n As Double, m As Double, i As Double, j As Double, k As Double
        n = Rango.Rows.Count: m = Rango.Columns.Count: k = n * m
        ReDim x(n, m)
        For i = 1 To n Step 1
            For j = 1 To m Step 1
                x(i, j) = Application.Large(Rango, k)
                k = k - 1
            Next j
        Next i
        SORT = x
    Else
        Exit Function
    End If
End Function

3
Що це за сорт? І чому ви кажете, що це "освічено"?
not2qubit

Зчитуючи код, здається, що він "сортує" весь двовимірний масив (взятий з аркуша Excel) по всьому масиву (а не за певним виміром). Тож значення змінять свої розмірні індекси. А потім результат повертається на аркуш.
ZygD

1
Хоча код може працювати для простих випадків, з цим кодом є багато проблем. Перше, що я помічаю, це використання Doubleзамість Longскрізь. По-друге, не враховується, якщо діапазон має кілька областей. Сортування прямокутника не здається корисним, і, звичайно, це не те, про що вимагав ОП (зокрема сказано, що немає власних рішень Excel / .Net). Крім того, якщо ви порівнюєте, чим простіше, тим краще "освіченіший", чи не Range.Sort()найкращим буде використання вбудованої функції?
Profex

0

Це те, що я використовую для сортування в пам'яті - його можна легко розширити для сортування масиву.

Sub sortlist()

    Dim xarr As Variant
    Dim yarr As Variant
    Dim zarr As Variant

    xarr = Sheets("sheet").Range("sing col range")
    ReDim yarr(1 To UBound(xarr), 1 To 1)
    ReDim zarr(1 To UBound(xarr), 1 To 1)

    For n = 1 To UBound(xarr)
        zarr(n, 1) = 1
    Next n

    For n = 1 To UBound(xarr) - 1
        y = zarr(n, 1)
        For a = n + 1 To UBound(xarr)
            If xarr(n, 1) > xarr(a, 1) Then
                y = y + 1
            Else
                zarr(a, 1) = zarr(a, 1) + 1
            End If
        Next a
        yarr(y, 1) = xarr(n, 1)
    Next n

    y = zarr(UBound(xarr), 1)
    yarr(y, 1) = xarr(UBound(xarr), 1)

    yrng = "A1:A" & UBound(yarr)
    Sheets("sheet").Range(yrng) = yarr

End Sub

0

Реалізація купівельного сорту . O (n log (n)) (як середній, так і найгірший випадок), нестабільний алгоритм сортування.

Використовуйте з:, Call HeapSort(A)де A- одновимірний масив варіантів, з Option Base 1.

Sub SiftUp(A() As Variant, I As Long)
    Dim K As Long, P As Long, S As Variant
    K = I
    While K > 1
        P = K \ 2
        If A(K) > A(P) Then
            S = A(P): A(P) = A(K): A(K) = S
            K = P
        Else
            Exit Sub
        End If
    Wend
End Sub

Sub SiftDown(A() As Variant, I As Long)
    Dim K As Long, L As Long, S As Variant
    K = 1
    Do
        L = K + K
        If L > I Then Exit Sub
        If L + 1 <= I Then
            If A(L + 1) > A(L) Then L = L + 1
        End If
        If A(K) < A(L) Then
            S = A(K): A(K) = A(L): A(L) = S
            K = L
        Else
            Exit Sub
        End If
    Loop
End Sub

Sub HeapSort(A() As Variant)
    Dim N As Long, I As Long, S As Variant
    N = UBound(A)
    For I = 2 To N
        Call SiftUp(A, I)
    Next I
    For I = N To 2 Step -1
        S = A(I): A(I) = A(1): A(1) = S
        Call SiftDown(A, I - 1)
    Next
End Sub

0

@Prasand Kumar, ось повна процедура сортування, заснована на концепціях Prasand:

Public Sub ArrayListSort(ByRef SortArray As Variant)
    '
    'Uses the sort capabilities of a System.Collections.ArrayList object to sort an array of values of any simple
    'data-type.
    '
    'AUTHOR: Peter Straton
    '
    'CREDIT: Derived from Prasand Kumar's post at: /programming/152319/vba-array-sort-function
    '
    '*************************************************************************************************************

    Static ArrayListObj As Object
    Dim i As Long
    Dim LBnd As Long
    Dim UBnd As Long

    LBnd = LBound(SortArray)
    UBnd = UBound(SortArray)

    'If necessary, create the ArrayList object, to be used to sort the specified array's values

    If ArrayListObj Is Nothing Then
        Set ArrayListObj = CreateObject("System.Collections.ArrayList")
    Else
        ArrayListObj.Clear  'Already allocated so just clear any old contents
    End If

    'Add the ArrayList elements from the array of values to be sorted. (There appears to be no way to do this
    'using a single assignment statement.)

    For i = LBnd To UBnd
        ArrayListObj.Add SortArray(i)
    Next i

    ArrayListObj.Sort   'Do the sort

    'Transfer the sorted ArrayList values back to the original array, which can be done with a single assignment
    'statement.  But the result is always zero-based so then, if necessary, adjust the resulting array to match
    'its original index base.

    SortArray = ArrayListObj.ToArray
    If LBnd <> 0 Then ReDim Preserve SortArray(LBnd To UBnd)
End Sub

0

Дещо пов’язане, але я також шукав власне рішення VBA Excel, оскільки вдосконалені структури даних (Словники тощо) не працюють у моєму середовищі. Наступне реалізує сортування через двійкове дерево у VBA:

  • Припускає, що масив заповнюється по одному
  • Видаляє дублікати
  • Повертає відокремлений рядок ( "0|2|3|4|9"), який потім можна розділити.

Я використав його для повернення необробленого відсортованого переліку рядків, вибраних для довільно вибраного діапазону

Private Enum LeafType: tEMPTY: tTree: tValue: End Enum
Private Left As Variant, Right As Variant, Center As Variant
Private LeftType As LeafType, RightType As LeafType, CenterType As LeafType
Public Sub Add(x As Variant)
    If CenterType = tEMPTY Then
        Center = x
        CenterType = tValue
    ElseIf x > Center Then
        If RightType = tEMPTY Then
            Right = x
            RightType = tValue
        ElseIf RightType = tTree Then
            Right.Add x
        ElseIf x <> Right Then
            curLeaf = Right
            Set Right = New TreeList
            Right.Add curLeaf
            Right.Add x
            RightType = tTree
        End If
    ElseIf x < Center Then
        If LeftType = tEMPTY Then
            Left = x
            LeftType = tValue
        ElseIf LeftType = tTree Then
            Left.Add x
        ElseIf x <> Left Then
            curLeaf = Left
            Set Left = New TreeList
            Left.Add curLeaf
            Left.Add x
            LeftType = tTree
        End If
    End If
End Sub
Public Function GetList$()
    Const sep$ = "|"
    If LeftType = tValue Then
        LeftList$ = Left & sep
    ElseIf LeftType = tTree Then
        LeftList = Left.GetList & sep
    End If
    If RightType = tValue Then
        RightList$ = sep & Right
    ElseIf RightType = tTree Then
        RightList = sep & Right.GetList
    End If
    GetList = LeftList & Center & RightList
End Function

'Sample code
Dim Tree As new TreeList
Tree.Add("0")
Tree.Add("2")
Tree.Add("2")
Tree.Add("-1")
Debug.Print Tree.GetList() 'prints "-1|0|2"
sortedList = Split(Tree.GetList(),"|")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.