You didn’t want an Excel-based solution but since I had the same problem today and wanted to test using other Office Applications functions I wrote the function below.
Limitations:
- 2-dimensional arrays;
- maximum of 3 columns as sort keys;
- depends on Excel;
Tested calling Excel 2010 from 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
This is an example on how to test the 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
If anybody tests this using other versions of office please post here if there are any problems.
Сортировка одномерного массива в VBA Excel по возрастанию или убыванию с числовым или текстовым сравнением числовых элементов. Сортировка выбором.
Сортировка массива выбором
Функция, осуществляющая сортировку выбором одномерного массива по возрастанию с числовым сравнением числовых элементов массива:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Function SortArray(myArray As Variant) As Variant Dim l As Long, u As Long, i1 As Long, i2 As Long, im As Long, tmp As Variant ‘Определение наименьшего индекса массива l = LBound(myArray) ‘Определение наибольшего индекса массива u = UBound(myArray) For i1 = l To u im = i1 For i2 = i1 To u ‘Поиск наименьшего элемента массива, начиная с элемента myArray(i1) If myArray(i2) < myArray(im) Then im = i2 Next ‘Если наименьший элемент не является текущим (im <> i1), ‘тогда наименьший элемент и текущий меняются местами If im <> i1 Then tmp = myArray(i1) myArray(i1) = myArray(im) myArray(im) = tmp End If Next SortArray = myArray End Function |
Внешний цикл сравнивает по очереди каждый элемент массива с наименьшем элементом, найденным вложенным циклом среди оставшихся элементов (с бóльшими индексами), и, если наименьший элемент myArray(im)
не является текущим элементом myArray(i1)
, они меняются местами.
Функция с выбором вида сортировки
Функция сортировки одномерного массива с дополнительным параметром mySort, который позволяет выбрать сортировку по возрастанию или убыванию и с числовым или текстовым сравнением числовых элементов массива:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Function SortArrayNew(myArray As Variant, mySort As Long) As Variant Dim l As Long, u As Long, i1 As Long, i2 As Long, im As Long, tmp As Variant l = LBound(myArray) u = UBound(myArray) For i1 = l To u im = i1 For i2 = i1 To u Select Case mySort Case Is = 0 If myArray(i2) < myArray(im) Then im = i2 Case Is = 1 If CStr(myArray(i2)) < CStr(myArray(im)) Then im = i2 Case Is = 2 If myArray(i2) > myArray(im) Then im = i2 Case Is = 3 If CStr(myArray(i2)) > CStr(myArray(im)) Then im = i2 End Select Next If im <> i1 Then tmp = myArray(i1) myArray(i1) = myArray(im) myArray(im) = tmp End If Next SortArrayNew = myArray End Function |
Значения, которые может принимать параметр mySort:
Значение | Вид сортировки |
---|---|
0 | по возрастанию с числовым сравнением чисел |
1 | по возрастанию с текстовым сравнением чисел |
2 | по убыванию с числовым сравнением чисел |
3 | по убыванию с текстовым сравнением чисел |
Пример сортировки массива
Пример использования разных видов сортировки одномерного массива в VBA Excel с выводом результатов на рабочий лист:
Sub Primer() Dim myArr As Variant, x As Variant, i As Long, n As Long For i = 1 To 4 myArr = Array(46, 25, «Лето», 508, 35, «лес», 11, 5, «25ф», «Лес», 45, 58, «лето», 350) myArr = SortArrayNew(myArr, i — 1) n = 1 For Each x In myArr Cells(n, i) = myArr(n — 1) n = n + 1 Next Next End Sub |
Результаты разных видов сортировки массива myArr:
слэн Пользователь Сообщений: 5192 |
кроме как на листе, конечно.. |
Вообще есть куча разнообразных способов и методов… Вот еще один: http://www.vbrussian.com/Article.asp?ID=97 P.S. Google рулит) |
|
слэн Пользователь Сообщений: 5192 |
а с использованием стандартных функций( Сишных, например) никто не видел? я тоже надыбал одну ссылку по реализации алгоритма quicksort на VBA, но уже нашел там ошибку.. |
New Пользователь Сообщений: 4581 |
|
New Пользователь Сообщений: 4581 |
|
В VBA насколько я понимаю, ф-ции swap нету. Значит, напрямую преобразовать Си-пример в код VBA не получится. Вот в этой теме — http://www.planetaexcel.ru/forum.php?thread_id=5274 (была указана выше) — Турбо-Ёж впроде бы предлагал подогнаный под Excel метод Fast Quick Sort. |
|
Блин, до конца не разобрался) Swap — это ж отдельная процедура) Тогда пример Турбо-Ежа — точно Fast Quick Sort. |
|
Потестил 2 способа Ежа и по ссылке http://www.vbrussian.com/Article.asp?ID=97 с помощью Так вот, сортировка Ежа на миллионе случайных чисел — 21 секунда, вторая сортировка — 7 секунд.. |
|
слэн Пользователь Сообщений: 5192 |
скачал алгоритм qsort с www.cpearson.com только там в «NumberOfArrayDimensions» надо заменить как минимум ex: NumberOfArrayDimensions = Ndx — 1 End Function а так довольно быстро работает. |
слэн Пользователь Сообщений: 5192 |
{quote}{login=Артем}{date=09.01.2009 07:35}{thema=}{post}Потестил 2 способа Ежа и по ссылке http://www.vbrussian.com/Article.asp?ID=97 с помощью Так вот, сортировка Ежа на миллионе случайных чисел — 21 секунда, вторая сортировка — 7 секунд.. по извлечению уникальных элементов посмотрите здесь: http://sql.ru/forum/actualthread.aspx?bid=46&tid=333152&pg=-1 сортировать не надо.. на миллионе не пробовал, но на 60000(в 2003 икселе) доли секунды.. |
New Пользователь Сообщений: 4581 |
В приложенном архиве 3 файла 1) сортировка от Chip Pearson, которую дал Слэн http://www.vbrussian.com/Article.asp?ID=97 3) сортировка взятая отсюда http://www.vbnet.ru/forum/show.aspx?id=90781&page=1 По моим результатам 3-й вариант самый быстрый. Если я не прав, поправьте меня. |
ZVI Пользователь Сообщений: 4328 |
Добрый вечер, Слэн! и всем Алгоритмов VBA-сортировки опубликовано достаточно много. Вот здесь хороший ресурс по методам сортировки на нескольких языках программирования: http://alglib.sources.ru/sorting/ Там же есть и статья по сравнению эффективности алгоритмов сортировки массивов: http://alglib.sources.ru/articles/sort.php Только советую творчески отнестись к коду и оценкам, так как из-за универсальности код не оптимизирован. И на VB (VBA) можно получить иные результаты эффективности. Эффективность сортировки сильно зависит от размера массива, типа данных, метода сортировки, компилятора и/или среды программирования. В частности, по моим оценкам, на обработках длинных строк при прочих равных условиях компилятор Borland C++ в 2 … 2.5 раза быстрее компилятора Visual C++. Но и функциями VBA можно написать код, который обрабатывает строки в несколько раз быстрее, чем некоторые другие встроенные VBA-функции, написанные на C(++), если вместо автоматизации по скорости компилятора для конкретной задачи написать более оптимальный код, понимая, где реальные тормоза: memory reallocation, adjusting of addresses etc. Известны также методы сортировки коллекций, но они неэффективны на больших массивах: http://www.dailydoseofexcel.com/archives/2004/06/02/sort-a-collection/ Впрочем, использование дополнительного индексного массива заслуживает внимания: http://www.source-code.biz/snippets/vbasic/ Индексный массив особенно насущен и для сортировки многомерных массивов. На мой взгляд, в дополнение к использованию индексного массива представляет интерес свопинг не самих переменных, а их адресов с помощью API CopyMemory (RtlMoveMemory). Подозреваю, что Excel как и поступает, но реальных тестов эффективности этого метода я не проводил. |
согласен с Павлом, метод с Vbnet самый быстрый — на моем ПК миллион значений обрабытывает за 5 сек, пирсоновский аж 34 секунды.(Не смотрел пока то что выложил ZVI) |
|
метод бинарных деревьев(при прочих равных) — 6,6 секунд однако… |
|
New Пользователь Сообщений: 4581 |
Хм, а кто знает, как запустить этот метод бинарных деревьев с одномерным массивом? )) Объявил массив Dim MyArr() As Double, i As Long ReDim MyArr(0 To 50000) Вызываю процедуру сортировки HeapSort MyArr(), 1 1 — т.е. одномерный массив (в процедуре написано указывать размерность) но процедура сразу заканчивается, т.к. в начале процедуры написано If N = 1# Then С размерностью 0 — выходит ошибка (ну, это логично) Файл прилагаю. |
New Пользователь Сообщений: 4581 |
ZVI, в твоём архиве в файле Sort_Routines.xls (где представлены различные методы сортировки) в модуле modHeapSort (метод бинарных деревьев) неправильно объявлены многие переменные, типа Dim base, n, nn, i, m As Long При таком объявлении, при сортировке 50000 целых чисел у меня был лучший результат 1500 мс, при правильном объявлении всех этим переменных лучшим результатом стало 1047 мс, т.е. почти 500 мс выигрыш. Я понимаю, это камень не в твой огород, а в огород автора файла. Но всё равно очень долго работает этот метод бинарных деревьев Кстати, в этом же файле в модуле modMain, автор файла явно пишет, что он предпочитает из всех методов QuickSort, вот эта строка varray2 = modQuickSort.Quicksort(varray) ‘Preferred Method of Sorting Ох, что-то я не пойму. Все говорят, что метод бинарных деревьев самый быстрый, но при тестировании он почему-то самый долгий )) Может у меня руки кривые? Разъясни, плиз ) Файл с мет. Бинар. деревьев из твоего файла прилагаю. Я пытаюсь найти самый максимально быстрый способ сортировки массивов на листе Excel, как текстовых, так и числовых. |
New Пользователь Сообщений: 4581 |
Потестировал я сортировку QuickSort из файла Sort_Routines.xls, которую так полюбил автор этого файла. При тестировании я чуть не умер… лучший результат … эм вам в миллисекундах сказать или лучше в минутах? )) В общем 252312 мс, на сколько я понимаю, это 4,2 минуты. Файл прикладываю. На сколько я понимаю, всё-таки самый быстрый пока остаётся 3-й вариант из моего поста post_44028.xls ( http://www.planetaexcel.ru/docs/forum_upload/post_44028.rar ), который я выложил выше в этой теме. Так? так… 5 утра … надо ложиться спать. Всем споки. |
New Пользователь Сообщений: 4581 |
По моему посту выше, где я не мог запустить сортировку с методом бинарных деревьев. Я просто неправильно прочитал название аргумента. Надо читать N — размер массива, а я прочитал «размерность массива» — из-за этого не мог запустить процедуру. В общем, я сегодня потестировал две версия сортировки методом бинарных деревьев. Оба они оказались не самыми лучшими. Или я, может, что-то делаю не так. Как я уже и сказал, пока лучшим остаётся 3-й вариант файла в посте http://www.planetaexcel.ru/docs/forum_upload/post_44028.rar 2 файла с бинарными деревьями выкладываю на вашего тестирования и анализа а я спать, всем споки |
ZVI Пользователь Сообщений: 4328 |
Насчет оценок методов я предупреждал |
слэн Пользователь Сообщений: 5192 |
да, вариант qsort без рекурсии — лучший, но почти в два раза медленнее икселевской сортировки непонятки: когда вызываю как процедуру, т.е например: call qsort(arr) если же вызывать как функцию: if qsort(arr) then: и второе — оправдано ли оформление функцией простых действий? типа swap — в одном месте в коде употребляется — не проще ли прямо там и записать алгоритм swap? хотя, конечно, это и несущественное замедление.. но если таких функций насовать туда поболе.. |
ZVI Пользователь Сообщений: 4328 |
В варианте Павла, работает и Call QuickSortNonRecursive(Rng) и просто QuickSortNonRecursive Rng. Насчет swap все правильно: для уменьшения времени лучше явно вписать перестановку в общую процедуру, чем многократно вызывать функцию. Сам вызов функции на любом языке программирования — это время, не говоря уже о времени на создание локальных переменных внутри функции при каждом вызове и еще, возможно, на приведение типов данных. |
New Пользователь Сообщений: 4581 |
Может кто-нибудь изменит макрос (QuickSort без рекурсии), как вы считаете будет быстрее, т.е. swap вставите внутрь процедуры? Чтобы, как говорится, вышла максимально быстрая процедура? (а то у меня что-то голова сегодня не работает) |
слэн Пользователь Сообщений: 5192 |
крутил-крутил.. кроме swap ничего улучшить не получается. ну памяти чуть сэкономил, но и это еще вопрос stack(1).Low = LBound(SortArray) ‘Сейчас указатель i указывает на начало правого подмассива, If i < ppos Then ‘правая часть больше |
New Пользователь Сообщений: 4581 |
Да, действительно быстрее. Спасибо, Слэн. Итак, выкладываю 2 варианта Они оба основаны на сортировке QuickSort без рекурсий, но с разными типами переменных в функции Swap (в одном случае переменные типа Variant, в другом String) P.S. Совместить два в одном, чтобы макрос быстро обрабатывал и текст и числа. У меня не вышло. |
ZVI Пользователь Сообщений: 4328 |
Павел, у Слэна как раз и сделан вариант как для строк, так и для чисел. В приложении немного переделанный файл для совместной сортировки строк и чисел. |
слэн Пользователь Сообщений: 5192 |
вот так вот осталось чуть-чуть |
слэн Пользователь Сообщений: 5192 |
интересно, ZVI, почему именно умножать на 2 при увеличении массива stack? это не слишком? ведь выход за пределы массива вовсе не обозначает, что потребуется еще столько же уровней, скорее наоборот.. можно даже предположить сколько понадобится по формуле: можно оценить как: (ub-i)/(ub-lb)*stackpos да и на самом деле, для случайных чисел , количество уровней колеблется в пределах: 10-11 на массиве из 65000 значений ps не лень вам ждать каждый раз пока массив создается? да икак в таком случае сравнивать методы? свой файл прилагаю. перед первой сортировкой(ну и , соответственно, по желанию) нажать «поменять массив» |
слэн Пользователь Сообщений: 5192 |
#30 11.01.2009 15:56:31 или умножение просто быстрее сложения? Живи и дай жить.. |
Here’s a multi-column and a single-column QuickSort for VBA, modified from a code sample posted by Jim Rech on Usenet.
Notes:
You’ll notice that I do a lot more defensive coding than you’ll see in most of the code samples out there on the web: this is an Excel forum, and you’ve got to anticipate nulls and empty values… Or nested arrays and objects in arrays if your source array comes from (say) a third-party realtime market data source.
Empty values and invalid items are sent to the end of the list.
To sort multi-column arrays, your call will be:
QuickSortArray MyArray,,,2
…Passing ‘2’ as the column to sort on and excluding the optional parameters that pass the upper and lower bounds of the search domain.
Sorting single-column arrays (vectors), instead use:
QuickSortVector Myarray
Here too excluding the optional parameters.
[EDITED] — fixed an odd formatting glitch in the <code> tags, which seem to have a problem with hyperlinks in code comments.
The Hyperlink I excised was Detecting an Array Variant in VBA.
Public Sub QuickSortArray(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1, Optional lngColumn As Long = 0)
On Error Resume Next
'Sort a 2-Dimensional array
' SampleUsage: sort arrData by the contents of column 3
'
' QuickSortArray arrData, , , 3
'
'Posted by Jim Rech 10/20/98 Excel.Programming
'Modifications, Nigel Heffernan:
' ' Escape failed comparison with empty variant
' ' Defensive coding: check inputs
Dim i As Long
Dim j As Long
Dim varMid As Variant
Dim arrRowTemp As Variant
Dim lngColTemp As Long
If IsEmpty(SortArray) Then
Exit Sub
End If
If InStr(TypeName(SortArray), "()") < 1 Then 'IsArray() is somewhat broken: Look for brackets in the type name
Exit Sub
End If
If lngMin = -1 Then
lngMin = LBound(SortArray, 1)
End If
If lngMax = -1 Then
lngMax = UBound(SortArray, 1)
End If
If lngMin >= lngMax Then ' no sorting required
Exit Sub
End If
i = lngMin
j = lngMax
varMid = Empty
varMid = SortArray((lngMin + lngMax) 2, lngColumn)
' We send 'Empty' and invalid data items to the end of the list:
If IsObject(varMid) Then ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a valid default member or property
i = lngMax
j = lngMin
ElseIf IsEmpty(varMid) Then
i = lngMax
j = lngMin
ElseIf IsNull(varMid) Then
i = lngMax
j = lngMin
ElseIf varMid = "" Then
i = lngMax
j = lngMin
ElseIf VarType(varMid) = vbError Then
i = lngMax
j = lngMin
ElseIf VarType(varMid) > 17 Then
i = lngMax
j = lngMin
End If
While i <= j
While SortArray(i, lngColumn) < varMid And i < lngMax
i = i + 1
Wend
While varMid < SortArray(j, lngColumn) And j > lngMin
j = j - 1
Wend
If i <= j Then
' Swap the rows
ReDim arrRowTemp(LBound(SortArray, 2) To UBound(SortArray, 2))
For lngColTemp = LBound(SortArray, 2) To UBound(SortArray, 2)
arrRowTemp(lngColTemp) = SortArray(i, lngColTemp)
SortArray(i, lngColTemp) = SortArray(j, lngColTemp)
SortArray(j, lngColTemp) = arrRowTemp(lngColTemp)
Next lngColTemp
Erase arrRowTemp
i = i + 1
j = j - 1
End If
Wend
If (lngMin < j) Then Call QuickSortArray(SortArray, lngMin, j, lngColumn)
If (i < lngMax) Then Call QuickSortArray(SortArray, i, lngMax, lngColumn)
End Sub
… And the single-column array version:
Public Sub QuickSortVector(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1)
On Error Resume Next
'Sort a 1-Dimensional array
' SampleUsage: sort arrData
'
' QuickSortVector arrData
'
' Originally posted by Jim Rech 10/20/98 Excel.Programming
' Modifications, Nigel Heffernan:
' ' Escape failed comparison with an empty variant in the array
' ' Defensive coding: check inputs
Dim i As Long
Dim j As Long
Dim varMid As Variant
Dim varX As Variant
If IsEmpty(SortArray) Then
Exit Sub
End If
If InStr(TypeName(SortArray), "()") < 1 Then 'IsArray() is somewhat broken: Look for brackets in the type name
Exit Sub
End If
If lngMin = -1 Then
lngMin = LBound(SortArray)
End If
If lngMax = -1 Then
lngMax = UBound(SortArray)
End If
If lngMin >= lngMax Then ' no sorting required
Exit Sub
End If
i = lngMin
j = lngMax
varMid = Empty
varMid = SortArray((lngMin + lngMax) 2)
' We send 'Empty' and invalid data items to the end of the list:
If IsObject(varMid) Then ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a default member or property
i = lngMax
j = lngMin
ElseIf IsEmpty(varMid) Then
i = lngMax
j = lngMin
ElseIf IsNull(varMid) Then
i = lngMax
j = lngMin
ElseIf varMid = "" Then
i = lngMax
j = lngMin
ElseIf VarType(varMid) = vbError Then
i = lngMax
j = lngMin
ElseIf VarType(varMid) > 17 Then
i = lngMax
j = lngMin
End If
While i <= j
While SortArray(i) < varMid And i < lngMax
i = i + 1
Wend
While varMid < SortArray(j) And j > lngMin
j = j - 1
Wend
If i <= j Then
' Swap the item
varX = SortArray(i)
SortArray(i) = SortArray(j)
SortArray(j) = varX
i = i + 1
j = j - 1
End If
Wend
If (lngMin < j) Then Call QuickSortVector(SortArray, lngMin, j)
If (i < lngMax) Then Call QuickSortVector(SortArray, i, lngMax)
End Sub
I used to use BubbleSort for this kind of thing, but it slows down, severely, after the array exceeds 1024 rows. I include the code below for your reference: please note that I haven’t provided source code for ArrayDimensions, so this will not compile for you unless you refactor it — or split it out into ‘Array’ and ‘vector’ versions.
Public Sub BubbleSort(ByRef InputArray, Optional SortColumn As Integer = 0, Optional Descending As Boolean = False) ' Sort a 1- or 2-Dimensional array. Dim iFirstRow As Integer Dim iLastRow As Integer Dim iFirstCol As Integer Dim iLastCol As Integer Dim i As Integer Dim j As Integer Dim k As Integer Dim varTemp As Variant Dim OutputArray As Variant Dim iDimensions As Integer iDimensions = ArrayDimensions(InputArray) Select Case iDimensions Case 1 iFirstRow = LBound(InputArray) iLastRow = UBound(InputArray) For i = iFirstRow To iLastRow - 1 For j = i + 1 To iLastRow If InputArray(i) > InputArray(j) Then varTemp = InputArray(j) InputArray(j) = InputArray(i) InputArray(i) = varTemp End If Next j Next i Case 2 iFirstRow = LBound(InputArray, 1) iLastRow = UBound(InputArray, 1) iFirstCol = LBound(InputArray, 2) iLastCol = UBound(InputArray, 2) If SortColumn InputArray(j, SortColumn) Then For k = iFirstCol To iLastCol varTemp = InputArray(j, k) InputArray(j, k) = InputArray(i, k) InputArray(i, k) = varTemp Next k End If Next j Next i End Select If Descending Then OutputArray = InputArray For i = LBound(InputArray, 1) To UBound(InputArray, 1) k = 1 + UBound(InputArray, 1) - i For j = LBound(InputArray, 2) To UBound(InputArray, 2) InputArray(i, j) = OutputArray(k, j) Next j Next i Erase OutputArray End If End Sub
This answer may have arrived a bit late to solve your problem when you needed to, but other people will pick it up when they Google for answers for similar problems.
Вступление
В отличие от платформы .NET, библиотека Visual Basic для приложений не включает процедуры сортировки массивов.
Существует два типа обходных путей: 1) реализация алгоритма сортировки с нуля или 2) использование подпрограмм сортировки в других общедоступных библиотеках.
Реализация алгоритма — Быстрая сортировка по одномерному массиву
Из функции сортировки массива VBA?
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
Использование библиотеки Excel для сортировки одномерного массива
Этот код использует класс Sort
в библиотеке объектов Microsoft Excel.
Для дальнейшего ознакомления см .:
-
Скопировать диапазон в виртуальный диапазон
-
Как скопировать выбранный диапазон в заданный массив?
Sub testExcelSort()
Dim arr As Variant
InitArray arr
ExcelSort arr
End Sub
Private Sub InitArray(arr As Variant)
Const size = 10
ReDim arr(size)
Dim i As Integer
' Add descending numbers to the array to start
For i = 0 To size
arr(i) = size - i
Next i
End Sub
Private Sub ExcelSort(arr As Variant)
' Ininitialize the Excel objects (required)
Dim xl As New Excel.Application
Dim wbk As Workbook
Set wbk = xl.Workbooks.Add
Dim sht As Worksheet
Set sht = wbk.ActiveSheet
' Copy the array to the Range object
Dim rng As Range
Set rng = sht.Range("A1")
Set rng = rng.Resize(UBound(arr, 1), 1)
rng.Value = xl.WorksheetFunction.Transpose(arr)
' Run the worksheet's sort routine on the Range
Dim MySort As Sort
Set MySort = sht.Sort
With MySort
.SortFields.Clear
.SortFields.Add rng, xlSortOnValues, xlAscending, xlSortNormal
.SetRange rng
.Header = xlNo
.Apply
End With
' Copy the results back to the array
CopyRangeToArray rng, arr
' Clear the objects
Set rng = Nothing
wbk.Close False
xl.Quit
End Sub
Private Sub CopyRangeToArray(rng As Range, arr)
Dim i As Long
Dim c As Range
' Can't just set the array to Range.value (adds a dimension)
For Each c In rng.Cells
arr(i) = c.Value
i = i + 1
Next c
End Sub
Example
From VBA array sort function?
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
Trojan52 0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
||||
1 |
||||
Метод быстрой сортировки03.07.2013, 13:57. Показов 9927. Ответов 38 Метки нет (Все метки)
Как отсортировать одномерный массив методом Быстрой сортировки?
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
03.07.2013, 13:57 |
Ответы с готовыми решениями: Алгоритм быстрой сортировки для двумерного массива. Получается, чем меньше столбцов, тем быстрее сортировка Как расписать «по шагам» процесс быстрой сортировки массива.
Предложить метод сортировки текстового массива, отличный от WordBasic.SortArray 38 |
6875 / 2807 / 533 Регистрация: 19.10.2012 Сообщений: 8,562 |
|
03.07.2013, 14:08 |
2 |
И чего бы не отсортировать диапазон на листе и не взять в массив верхушку (в двумерный)?
0 |
0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
|
03.07.2013, 14:19 [ТС] |
3 |
И чего бы не отсортировать диапазон на листе и не взять в массив верхушку (в двумерный)? Такое уж задание? Сделать диалог выбора сортировки «Пузырьковая и Быстрая». С Пузырьковой разобрался, а вот с Быстрой туплю по-жесткому!
0 |
6875 / 2807 / 533 Регистрация: 19.10.2012 Сообщений: 8,562 |
|
03.07.2013, 14:22 |
4 |
Я наизусть не знаю — но где-тут ведь была тема со всеми сортировками.
0 |
призрак 3261 / 889 / 119 Регистрация: 11.05.2012 Сообщений: 1,702 Записей в блоге: 2 |
|
03.07.2013, 21:08 |
5 |
ключевое слово для поиска по форуму: quicksort
0 |
Trojan52 0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
||||
04.07.2013, 10:49 [ТС] |
6 |
|||
Как отсортировать одномерный массив методом Быстрой сортировки?
0 |
Trojan52 0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
||||
04.07.2013, 12:07 [ТС] |
7 |
|||
При работе скрипта вылетает ошибка «Out of stack space»! Как исправить не понимаю! Может есть какая-нибудь ошибка?
0 |
Dragokas 17992 / 7618 / 890 Регистрация: 25.12.2011 Сообщений: 11,351 Записей в блоге: 17 |
||||
04.07.2013, 12:54 |
8 |
|||
и не одна.
Добавлено через 4 минуты
1 |
Trojan52 0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
||||||||
04.07.2013, 13:03 [ТС] |
9 |
|||||||
и не одна. Не работает! Мой скрипт должен выполнять «Быструю сортировку»! Твой скрипт не сортирует ее до конца! Добавлено через 1 минуту
Trojan52, а зачем дубли темы создаете, а? Нехорошо В той теме никто не отвечал, а как удалять их я не знаю, ибо новичок! Добавлено через 3 минуты
Работает только так:
0 |
4377 / 661 / 36 Регистрация: 17.01.2010 Сообщений: 2,134 |
|
04.07.2013, 13:36 |
10 |
Вчера была Ваша тема про переменные. Я там как раз и говорил Вам ( и Султанов) про передачу аргументов в процедуру. А здесь Вы именнто это делаете, но используете сокращенную запись ( без присваивания :=), что тоже правильно по синтаксису языка. Ваша запись Call QSort (intArr, low, j) звучит так — вызвать процедуру QSort и передать ей аргументы intArr, low, j.
0 |
Trojan52 0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
||||||||
04.07.2013, 13:47 [ТС] |
11 |
|||||||
Вчера была Ваша тема про переменные. Я там как раз и говорил Вам ( и Султанов) про передачу аргументов в процедуру. А здесь Вы именнто это делаете, но используете сокращенную запись ( без присваивания :=), что тоже правильно по синтаксису языка. Ваша запись Не совсем понял что значит «(без присваивания :=)» Добавлено через 6 минут
Вчера была Ваша тема про переменные. Я там как раз и говорил Вам ( и Султанов) про передачу аргументов в процедуру. А здесь Вы именнто это делаете, но используете сокращенную запись ( без присваивания :=), что тоже правильно по синтаксису языка. Ваша запись Вот код, в котором почти в конце вызывается эта процедура!
В нем присутствует пузырьковая сортировка и переход к другой процедуре, где должна выполняться «Быстрая сортировка!»Вот эта процедура
Скорее всего я где-то сильно затупил, но где?
0 |
4377 / 661 / 36 Регистрация: 17.01.2010 Сообщений: 2,134 |
|
04.07.2013, 13:57 |
12 |
У Вас есть процедура с обязательными аргументами — Sub QSort(a, b, c). При ее вызове (Call) передаете ей аргументы. Можно разширенно — QSort(a:=intArr, b:=low, c:=j), а можна сокращенно, но обязательно соблюдать очередность (при написании, редактор должен показывать посказку) — QSort (intArr, low, j). Добавлено через 6 минут
0 |
0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
|
04.07.2013, 14:01 [ТС] |
13 |
Делаете две процедуры с аргументами (QSort расписано правильно). Одна — для пузырьковой (пусть QSort1(аргументы)), вторая — для быстрой (пусть QSort2(аргументы)). И поочереди вызываете — сохраняете где-то результаты. Можно совместить, но всеравно желательно результары разделить (они должны бы быть одинаковые — но так будет нагляднее). Разница должна быть (не обязательно) в времени. Не в этом дело! Высвечивается MsgBox, если Нажмешь «Да», то пройдет пузырьковая сортировка, если «Нет», то быстрая, а если нажата отмена, то Идет запись без сортировки!
0 |
Dragokas 17992 / 7618 / 890 Регистрация: 25.12.2011 Сообщений: 11,351 Записей в блоге: 17 |
||||
04.07.2013, 14:08 |
14 |
|||
Trojan52, да, сорри, не учел момент, что здесь рекурсия: нужно заменить строку 6 на:
1 |
4377 / 661 / 36 Регистрация: 17.01.2010 Сообщений: 2,134 |
|
04.07.2013, 14:16 |
15 |
Киньте лист с данными, которые Вы выделяете и сортируете. Прогоню у себя. Добавлено через 3 минуты
1 |
0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
|
04.07.2013, 14:16 [ТС] |
16 |
Киньте лист с данными, которые Вы выделяете и сортируете. Прогоню у себя. Прилагаю архив! С моим решением!
0 |
0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
|
04.07.2013, 14:29 [ТС] |
17 |
Поздно увидел, что Dragokas уже разобрался. Не разобрался, это ничего не изменило! Посмотрите код, если не сложно!
0 |
4377 / 661 / 36 Регистрация: 17.01.2010 Сообщений: 2,134 |
|
04.07.2013, 14:35 |
18 |
Посмотрю обязательно, ну у меня еще и работа… Не переживайте, все будет нормально. А пока вот-что. Гланул на код. Там работа с выделенным диапазоном (Select). Вы его вручную выделяете? И идет речь о D4:G15?
0 |
0 / 0 / 0 Регистрация: 24.06.2013 Сообщений: 71 |
|
04.07.2013, 14:38 [ТС] |
19 |
Поздно увидел, что Dragokas уже разобрался. Все равно не работает! Он ничего не изменил этой строчкой! Добавлено через 55 секунд
Вы его вручную выделяете? Да, диапазон выделяется вручную!
0 |
4377 / 661 / 36 Регистрация: 17.01.2010 Сообщений: 2,134 |
|
04.07.2013, 14:53 |
20 |
Не могу понять, что Вы имеете ввиду под переменной low?
1 |