Сортиране на групи от редове Excel VBA Macro

Имам проблем да разбера как да създам алгоритъм за сортиране във VBA, който сортира и разменя групи от редове (няколко реда наведнъж). Написах успешен алгоритъм за сортиране, използвайки масив по-долу:

Function SortArray(ByRef arrToSort As Variant)
Dim aLoop As Long, aLoop2 As Long
Dim str1 As String
Dim str2 As String
For aLoop = 1 To UBound(arrToSort)
   For aLoop2 = aLoop To UBound(arrToSort)
        If UCase(arrToSort(aLoop2)) < UCase(arrToSort(aLoop)) Then
            str1 = arrToSort(aLoop)
            str2 = arrToSort(aLoop2)
            arrToSort(aLoop) = str2
            arrToSort(aLoop2) = str1
        End If
    Next aLoop2
Next aLoop
SortArray = arrToSort

(където всеки елемент е елемент от масив), но сега искам да сортирам чрез размяна на редове или групи от редове. Ще обясня какво имам предвид по-долу.

Имам работен лист със заглавки в горната част и редове с данни отдолу:

Работен лист

Искам да напиша команда, която работи като горния алгоритъм. ОБАЧЕ, вместо да разменям елементи от масив, искам да разменям цели групи от редове. Header3 ((Може да бъде произволен низ) определя групирането. Всички групи в работния лист са сортирани индивидуално и групиране.

За да направя размяна на групирани редове, написах следния под RowSwapper(), който приема два низа, съдържащи редовете за размяна. (напр. във формата rws1 = "3:5").

Public Sub RowSwapper(ByVal rws1 As String, ByVal rws2 As String)
'ACCOMODATE VARIABLE ROW LENGTHS!!!!
    ActiveSheet.Rows(rws1).Cut
    ActiveSheet.Rows(rws2).Insert Shift:=xlDown
    ActiveSheet.Rows(rws2).Cut
    ActiveSheet.Rows(rws1).Insert Shift:=xlDown
    MsgBox "RowSwapper: row" & rws1 & "swapped with row " & rws2
End Sub

Някакви идеи? Моята стратегия, включително код, е посочена по-долу:

МОЯТА СТРАТЕГИЯ: Имам масивите prLst и srtdPrLst. prLst е масив от приоритети за сортиране. Позицията на приоритета в prLst е колоната (заглавката), към която се отнася. srtdPrLst, е масив, съдържащ тези приоритети, сортирани във възходящ ред (напр. 1,2,3....)

Преминавам през srtdPrLst, докато извиквам функцията FindPosition, за да намеря позиция на всеки приоритет. Връщам се назад, за да сортирам в правилния ред.

За да сортирам групи от редове, след това използвам същата техника като кода на SortArray по-горе. Трябва обаче да събера редовете, в които съществува група. За да направя това, имам два Do While цикъла, вложени под for циклите, по един за всяка група (тъй като сравнявам две групи). Тези редове се съхраняват в променливи grpCnt1 (за първата група за сравнение) и grpCnt1 (за втората група за сравнение).

Тъй като отделните групи вече са сортирани, трябва да сравня само първия ред на всяка група. Сравнявам низовете grp1Val с grp2Val с проста инструкция If. Ако низовете не са в азбучен ред, извиквам rowSwapper (посочен по-горе), за да ги разменя.

Описаният код е по-долу:

lstRowVal = Int(ActiveSheet.Range("AB" & totCount).Value) 'Индексът в масива prLst е колоната, на която е присвоен приоритет' следователно, pos = номер на колона 'Сортира назад, за да получи приоритети в подходящ ред 'MsgBox "marker = " & маркер

For prior2 = Int(UBound(srtdPrLst)) To 1 Step -1
    MsgBox "prior2 = " & prior2
    If Int(srtdPrLst(prior2)) > 0 Then
        pos = FindPosition(Int(srtdPrLst(prior2)), prLst)

        'Algorithm to sort groups
        For lLoop = 2 To lstRowVal '2 b/c Starts at row below headers


            'Find first group to compare
            grp1Val = ActiveSheet.Range(Mid(alphabet, pos, 1) & lLoop).Value
            hdToGrp1Val = ActiveSheet.Range(Mid(alphabet, hdrMrkr, 1) & lLoop).Value

            Do
                'nextGrp1Val = ActiveSheet.Range(Mid(alphabet, pos, 1) & (lLoop + grpCnt1)).Value
                nxtHdToGrp1 = ActiveSheet.Range(Mid(alphabet, hdrMrkr, 1) & (lLoop + grpCnt1)).Value
                grpCnt1 = grpCnt1 + 1
            Loop While nxtHdToGrp1 = hdToGrp1Val


           For lLoop2 = lLoop To lstRowVal 

                'Find second group to compare
                grp2Val = ActiveSheet.Range(Mid(alphabet, pos, 1) & lLoop2).Value
                hdToGrp2Val = ActiveSheet.Range(Mid(alphabet, hdrMrkr, 1) & lLoop2).Value

                Do
                    nxtHdToGrp2 = ActiveSheet.Range(Mid(alphabet, hdrMrkr, 1) & (lLoop2 + grpCnt2)).Value
                    grpCnt2 = grpCnt2 + 1
                Loop While nxtHdToGrp2 = hdToGrp2Val

                If UCase(grp2Val) < UCase(grp1Val) Then
                    RowSwapper lLoop & ":" & (lLoop + grpCnt1), lLoop2 & ":" & (lLoop2 + grpCnt2) 
                End If

                grp2Val = ""
                lLoop2 = lLoop2 + grpCnt2
                grpCnt2 = 0

            Next lLoop2


            grp1Val = ""
            lLoop = lLoop + grpCnt1
            grpCnt1 = 0

        Next lLoop
    End If
Next prior2

person H3lue    schedule 12.07.2011    source източник
comment
описанието ти е двусмислено. показването на пример за начало и за желания резултат може да помогне.   -  person nicolas    schedule 13.07.2011
comment
Опитвали ли сте да използвате таблица за това? Те са идеални за бита за сортиране и филтриране.   -  person jonsca    schedule 15.07.2011
comment
Доколкото знам, таблицата на excel няма възможностите за условно сортиране, които търся. Редовете трябва да бъдат заключени заедно, а групите трябва да бъдат заключени заедно и сортирани в списъка.   -  person H3lue    schedule 15.07.2011
comment
Не мога да изтегля файла, без да се регистрирам в този сайт, което не планирам да правя. Не разбирам напълно какво се опитвате да направите и какъв точно е проблемът с използването на .sort, но вие сте наясно, че ако искате да направите сортиране на колони A, B, C, можете също да постигнете същия резултат, като направите: сортирайте C, сортирайте B, сортирайте A   -  person Eddy    schedule 11.08.2011
comment
Поставил съм изображение отгоре, което описва сортирането. Предполагам, че листът ще бъде подреден на случаен принцип в началото.   -  person H3lue    schedule 15.08.2011


Отговори (1)


Съгласен съм, че въпросът все още е малко неясен. Опитвали ли сте да направите сортиране от Data>Sort... Можете да сортирате с помощта на множество ключове и да използвате персонализирани списъци.

Освен това, тъй като казахте, че искате някои насоки за VBA...:) Не мисля, че неща като

Dim letString, idLabel, curCell As String

прави това, което очаквате. Това, което всъщност се случва тук е

Dim letString as Variant, idLabel as Variant, curCell As String

защото не указвате след всяка променлива. Предполагам, че това, което искате тук, всъщност е:

Dim letString as String, idLabel as String, curCell As String

Второ, ако сте загрижени за ефективността като в последния си коментар, тогава бих избегнал използването на метода .select за манипулиране на диапазони. Можете да направите всичко в ексел без него. Това е просто допълнителна тежест. Така че вместо да правите нещо като Selction.Resize(1).Select, можете да регистрирате местоположенията на началото и края на вашия rand в цяло число променлива, след което да го промените в обект на диапазон, след като всичките ви критерии са изпълнени. Можете да подадете този обект на диапазон във вашата функция за сортиране.

Просто нещо за дъвчене.

person Brad    schedule 02.08.2011
comment
Научих много, откакто започнах този код, и разбрах, че трябва да го разделя на множество подзадачи, за да предам променливи, за да може програмата да работи по-ефективно. По-горе публикувам новия код (съдържащ само подчинението, с което имам проблеми). Дано стане по-ясно. - person H3lue; 02.08.2011