Сортировка групп строк 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

(где каждый элемент является элементом массива), но теперь я хочу отсортировать, заменив строки или группы строк. Я объясню, что я имею в виду ниже.

У меня есть рабочий лист с заголовками вверху и строками данных внизу:

Рабочий лист

Я хочу написать команду, которая работает по алгоритму выше. ОДНАКО, вместо замены элементов массива я хочу поменять местами целые группы строк. Заголовок3 ((может быть любой строкой) определяет группировку. Все группы на листе сортируются индивидуально и группируются.

Чтобы поменять местами сгруппированные строки, я написал следующую подпрограмму 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 = " & 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, вы также можете добиться того же результата, выполнив: сортировка С, сортировка Б, сортировка А   -  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 для манипулирования диапазонами. Вы можете делать все в excel без него. Это просто дополнительная нагрузка. Таким образом, вместо того, чтобы делать что-то вроде Selction.Resize(1).Select, вы можете зарегистрировать местоположения начала и конца вашего ранда в целочисленной переменной, а затем изменить ее на объект диапазона, как только все ваши критерии будут выполнены. Вы можете передать этот объект диапазона в свою функцию сортировки.

Просто есть что пожевать.

person Brad    schedule 02.08.2011
comment
Я многому научился с тех пор, как начал этот код, и понял, что мне нужно разбить его на несколько подпрограмм для передачи переменных, чтобы программа работала более эффективно. Выше я публикую новый код (содержащий только подпрограмму, с которой у меня проблемы). Надеюсь будет понятнее. - person H3lue; 02.08.2011