Суть макроса: выбираем ячейки через InputBox (можно, удерживая Control, выбрать несколько диапазонов), код сортирует значения, пустые ячейки превращая в пробел, список очищается от дубликатов и пропусков и выводится в указанную пользователем (опять InputBox) ячейку. По идее сортироваться должны любые значения без разбора - цифры, не цифры.
Предыстория: недавно на форуме нашёл ЭТУ ТЕМУ. Подумал, что интересно было бы написать на это дело макрос. Нашёл алгоритм сортировки пузырьком, любезно оставленный на форуме Николаем, и загорелся идеей сделать шажок к освоению новой для себя области программирования.
Код программы:
Очевидно, не самый быстрый на диком западе, т.к. "пузырьки" - это, наверно, первое, что пришло в голову человечеству на тему организующих алгоритмов.
[vba]
Код
Option Explicit Option Base 1
Sub Rio_Sort()
'Author: Roman Rioran Voronov 'Date: the 14-th of October, 2014 'Feedback: voronov_rv@mail.ru
' Макрос предлагает выбрать диапазон ячеек, из значений которых создаст отсортированный список 'без дубликатов. Пустые ячейки и ячейки с пробелом игнорируются. В конце макрос прелагает выбрать 'диапазон, в первую ячейку которого итоговый список будет вставлен.
' This subroutine allows User to select range, from where sorted list of values will be recei- 'ved. Doublicates, empty cells and cells with a single space value will be ignored. As conclusion 'User have to select cell, where final list will be pasted.
Dim rngA As Range, rngX As Range 'To fill arrX with values Dim arrX, ValueX As String 'For sorting values Dim arrY, ValueY As Long 'For final results Dim A, B As Long 'For bubble sorting and selection Dim X As Long 'rngA.count Dim Ring As Long 'How deep our circle is Dim Permission As Byte 'If 0 then exit Do
Set rngA = Application.InputBox(Prompt:="Выберите диапазон, который будет отсортирован без дубликатов.", Title:="Range Select", Type:=8)
For Each rngX In rngA X = X + 1 arrX(X, 1) = CStr(rngX.Value) Next rngX
Set rngA = Nothing: Set rngX = Nothing
For A = 1 To X For B = 1 To X + 1 - A Permission = 1 Ring = 1 If arrX(B, 1) = "" Then arrX(B, 1) = " " If arrX(B, 1) <> arrX(B + 1, 1) Then Do While Permission = 1 If Ring > Application.Min(Len(arrX(B, 1)), Len(arrX(B + 1, 1))) Then Exit Do If Asc(Mid(arrX(B, 1), Ring, 1)) > Asc(Mid(arrX(B + 1, 1), Ring, 1)) Then ValueX = arrX(B, 1) arrX(B, 1) = arrX(B + 1, 1) arrX(B + 1, 1) = ValueX Permission = 0 ElseIf Asc(Mid(arrX(B, 1), Ring, 1)) = Asc(Mid(arrX(B + 1, 1), Ring, 1)) Then Ring = Ring + 1 Else Exit Do End If Loop End If Next B Next A
B = 1 For A = 1 To X - 1 If arrX(A, 1) <> arrX(A + 1, 1) Then If arrX(A, 1) <> " " Then arrY(B, 1) = arrX(A, 1) B = B + 1 End If End If Next A
arrY(B, 1) = arrX(X, 1)
Set rngA = Application.InputBox(Prompt:="Выберите, куда вставить итоговый список.", Title:="Range Select", Type:=8)
rngA.Cells(1, 1).Resize(X, 1).Value = arrY
End Sub
[/vba]
Буду рад комментариям, отзывам и советам!
Всем привет и хорошего настроения!
Суть макроса: выбираем ячейки через InputBox (можно, удерживая Control, выбрать несколько диапазонов), код сортирует значения, пустые ячейки превращая в пробел, список очищается от дубликатов и пропусков и выводится в указанную пользователем (опять InputBox) ячейку. По идее сортироваться должны любые значения без разбора - цифры, не цифры.
Предыстория: недавно на форуме нашёл ЭТУ ТЕМУ. Подумал, что интересно было бы написать на это дело макрос. Нашёл алгоритм сортировки пузырьком, любезно оставленный на форуме Николаем, и загорелся идеей сделать шажок к освоению новой для себя области программирования.
Код программы:
Очевидно, не самый быстрый на диком западе, т.к. "пузырьки" - это, наверно, первое, что пришло в голову человечеству на тему организующих алгоритмов.
[vba]
Код
Option Explicit Option Base 1
Sub Rio_Sort()
'Author: Roman Rioran Voronov 'Date: the 14-th of October, 2014 'Feedback: voronov_rv@mail.ru
' Макрос предлагает выбрать диапазон ячеек, из значений которых создаст отсортированный список 'без дубликатов. Пустые ячейки и ячейки с пробелом игнорируются. В конце макрос прелагает выбрать 'диапазон, в первую ячейку которого итоговый список будет вставлен.
' This subroutine allows User to select range, from where sorted list of values will be recei- 'ved. Doublicates, empty cells and cells with a single space value will be ignored. As conclusion 'User have to select cell, where final list will be pasted.
Dim rngA As Range, rngX As Range 'To fill arrX with values Dim arrX, ValueX As String 'For sorting values Dim arrY, ValueY As Long 'For final results Dim A, B As Long 'For bubble sorting and selection Dim X As Long 'rngA.count Dim Ring As Long 'How deep our circle is Dim Permission As Byte 'If 0 then exit Do
Set rngA = Application.InputBox(Prompt:="Выберите диапазон, который будет отсортирован без дубликатов.", Title:="Range Select", Type:=8)
For Each rngX In rngA X = X + 1 arrX(X, 1) = CStr(rngX.Value) Next rngX
Set rngA = Nothing: Set rngX = Nothing
For A = 1 To X For B = 1 To X + 1 - A Permission = 1 Ring = 1 If arrX(B, 1) = "" Then arrX(B, 1) = " " If arrX(B, 1) <> arrX(B + 1, 1) Then Do While Permission = 1 If Ring > Application.Min(Len(arrX(B, 1)), Len(arrX(B + 1, 1))) Then Exit Do If Asc(Mid(arrX(B, 1), Ring, 1)) > Asc(Mid(arrX(B + 1, 1), Ring, 1)) Then ValueX = arrX(B, 1) arrX(B, 1) = arrX(B + 1, 1) arrX(B + 1, 1) = ValueX Permission = 0 ElseIf Asc(Mid(arrX(B, 1), Ring, 1)) = Asc(Mid(arrX(B + 1, 1), Ring, 1)) Then Ring = Ring + 1 Else Exit Do End If Loop End If Next B Next A
B = 1 For A = 1 To X - 1 If arrX(A, 1) <> arrX(A + 1, 1) Then If arrX(A, 1) <> " " Then arrY(B, 1) = arrX(A, 1) B = B + 1 End If End If Next A
arrY(B, 1) = arrX(X, 1)
Set rngA = Application.InputBox(Prompt:="Выберите, куда вставить итоговый список.", Title:="Range Select", Type:=8)
Почему вы так решили? Потому что вы так привыкли? Я, вот, например, давно уже привык к тому, что в локализации ( по коду chr() ) букоффка Ё находится либо до русского алфавита, либо после. Но никак не "внутрях". Желаете сделать "правильно по вашему ИМХО" - сделайте. Но, плиз, без критики в сторону создателя алгоритма... и кода...
И да, для начала попробуйте заменить chr() на chrW() :)
Почему вы так решили? Потому что вы так привыкли? Я, вот, например, давно уже привык к тому, что в локализации ( по коду chr() ) букоффка Ё находится либо до русского алфавита, либо после. Но никак не "внутрях". Желаете сделать "правильно по вашему ИМХО" - сделайте. Но, плиз, без критики в сторону создателя алгоритма... и кода...
И да, для начала попробуйте заменить chr() на chrW() :)AndreTM
Skype: andre.tm.007 Donate: Qiwi: 9517375010
Сообщение отредактировал AndreTM - Четверг, 16.10.2014, 02:52
Похоже, что буквы "е" и "ё" - равноправные "синонимы" и сортировка слов, начинающихся с них, определяется последующими символами, начиная со второго. Вот как отсортировалось по возрастанию стандартной сортировкой Excel:
ёб (извините!) Евпатория ЕГЭ ёж ёкарный бабай Ёксель-моксель ел енот ёперный театр естествознание
Похоже, что буквы "е" и "ё" - равноправные "синонимы" и сортировка слов, начинающихся с них, определяется последующими символами, начиная со второго. Вот как отсортировалось по возрастанию стандартной сортировкой Excel:
ёб (извините!) Евпатория ЕГЭ ёж ёкарный бабай Ёксель-моксель ел енот ёперный театр естествознаниеGustav
SLAVICK, спасибо, что обратили внимание на эту особенность. Если бы кто-то хотел получить список, отсортированный по секциям в, например, энциклопедии - надо было бы допилить дополнительный механизм обработки буквы ё. Например, превращать её в число буквы "е" плюс 0,5.
AndreTM, благодарю за наводку на chrW - c ним работать интереснее =) Ради забавы посмотрел полный набор символов (MSE 2007+):
[vba]
Код
Sub ChrW_Tester()
Dim X As Long
Application.ScreenUpdating = False
For X = -32768 To 65535 Cells(X + 32769, 1).Value = ChrW(X) Next X
Application.ScreenUpdating = True
End Sub
[/vba] Gustav, занятное наблюдение =)
SLAVICK, спасибо, что обратили внимание на эту особенность. Если бы кто-то хотел получить список, отсортированный по секциям в, например, энциклопедии - надо было бы допилить дополнительный механизм обработки буквы ё. Например, превращать её в число буквы "е" плюс 0,5.
AndreTM, благодарю за наводку на chrW - c ним работать интереснее =) Ради забавы посмотрел полный набор символов (MSE 2007+):
[vba]
Код
Sub ChrW_Tester()
Dim X As Long
Application.ScreenUpdating = False
For X = -32768 To 65535 Cells(X + 32769, 1).Value = ChrW(X) Next X
Нет не потому. Просто я сталкивался уже с подобной проблемой, когда делал автоматическое оглавление с группировкой по букве. так вот в Украинском языке также есть такие буквы ("і", "ї"). И то, что я знаю, что эти буквы находятся до а - конечному потребителю объяснить сложно. . Есть алфавит - это эталон как должно сортироваться(если это будут использовать другие пользователи). Далеко не все из них знают про 255 символов и что код символа "ё" = 184, а "а" = 224
Нет не потому. Просто я сталкивался уже с подобной проблемой, когда делал автоматическое оглавление с группировкой по букве. так вот в Украинском языке также есть такие буквы ("і", "ї"). И то, что я знаю, что эти буквы находятся до а - конечному потребителю объяснить сложно. . Есть алфавит - это эталон как должно сортироваться(если это будут использовать другие пользователи). Далеко не все из них знают про 255 символов и что код символа "ё" = 184, а "а" = 224
делал автоматическое оглавление с группировкой по букве
SLAVICK, звучит как будто у Вас есть пара идей, как обойти это дело =)
Я думаю можно было бы создать вспомогательный массив, в котором задана человеко-угодная последовательность алфавита и цифр в первом столбце и индикатор строки во втором. Символу можно было бы присвоить значение по индикатору, а если совпадений нет, присвоить значение из ChrW() + 40'000. И на основании этих значений применить сортирування бульбашкою.
делал автоматическое оглавление с группировкой по букве
SLAVICK, звучит как будто у Вас есть пара идей, как обойти это дело =)
Я думаю можно было бы создать вспомогательный массив, в котором задана человеко-угодная последовательность алфавита и цифр в первом столбце и индикатор строки во втором. Символу можно было бы присвоить значение по индикатору, а если совпадений нет, присвоить значение из ChrW() + 40'000. И на основании этих значений применить сортирування бульбашкою.Rioran
Роман, Москва, voronov_rv@mail.ru Яндекс-Деньги: 41001312674279
Похоже, что буквы "е" и "ё" - равноправные "синонимы" и сортировка слов, начинающихся с них, определяется последующими символами, начиная со второго. Вот как отсортировалось по возрастанию стандартной сортировкой Excel
Вы правы в Экселе так и есть. Недостаток это или преимущество каждый определяет для себя сам. Я же склонен считать, что это скорее всего первоначальное упущение создателей офиса,и попытка потом это исправить В интерфейсе для простых пользователей - исправили, а в ВБА не стали
Похоже, что буквы "е" и "ё" - равноправные "синонимы" и сортировка слов, начинающихся с них, определяется последующими символами, начиная со второго. Вот как отсортировалось по возрастанию стандартной сортировкой Excel
Вы правы в Экселе так и есть. Недостаток это или преимущество каждый определяет для себя сам. Я же склонен считать, что это скорее всего первоначальное упущение создателей офиса,и попытка потом это исправить В интерфейсе для простых пользователей - исправили, а в ВБА не стали SLAVICK
звучит как будто у Вас есть пара идей, как обойти это дело =)
Я делал так: заменял букву "ё" на "еяя" - сортировал, а потом наоборот "еяя" заменял на "ё" Мне не попадались слова с буквосочетаниями "еяя", поэтому у меня работало. Но теоретически возможно встретить такое сочетание... тогда будут ошибки
звучит как будто у Вас есть пара идей, как обойти это дело =)
Я делал так: заменял букву "ё" на "еяя" - сортировал, а потом наоборот "еяя" заменял на "ё" Мне не попадались слова с буквосочетаниями "еяя", поэтому у меня работало. Но теоретически возможно встретить такое сочетание... тогда будут ошибки SLAVICK
Иногда все проще чем кажется с первого взгляда.
Сообщение отредактировал SLAVICK - Четверг, 16.10.2014, 22:12
"еяя" ... теоретически возможно встретить такое сочетание...
Например, на производстве, где маркируют детали последовательностями букв, или при работе с аббревиатурами. Тогда склоняюсь больше к выборочной замене подобных символов на ближайший: ChrW() + 0,5
"еяя" ... теоретически возможно встретить такое сочетание...
Например, на производстве, где маркируют детали последовательностями букв, или при работе с аббревиатурами. Тогда склоняюсь больше к выборочной замене подобных символов на ближайший: ChrW() + 0,5Rioran
Роман, Москва, voronov_rv@mail.ru Яндекс-Деньги: 41001312674279
Вы спросили я ответил У меня не было необходимости усложнять, так как работа была со стандартными словами. нужно было срочно найти решение - это было самое простое, что я смог тогда придумать. Можно конечно не "еяя", а "еяяяяя" - тогда вероятность существенно уменьшается К сожалению я пока не работал с ChrW - поэтому ничего по этому поводу сказать не могу. Но будет повод изучить
Вы спросили я ответил У меня не было необходимости усложнять, так как работа была со стандартными словами. нужно было срочно найти решение - это было самое простое, что я смог тогда придумать. Можно конечно не "еяя", а "еяяяяя" - тогда вероятность существенно уменьшается К сожалению я пока не работал с ChrW - поэтому ничего по этому поводу сказать не могу. Но будет повод изучить SLAVICK
думаю можно было бы создать вспомогательный массив, в котором задана человеко-угодная последовательность алфавита
:) Ну да. При создании "конечных пользовательских интерфейсов" поможет именно и только словарь (или несколько словарей), или вообще любой механизм, считывающий из базы/создающий сам необходимые списки. Полагаться на то, что "внутренние" наборы данных приложения навечно останутся неизменными - по меньшей мере, глупомалопрофессионально... Особенно в приложениях M$
думаю можно было бы создать вспомогательный массив, в котором задана человеко-угодная последовательность алфавита
:) Ну да. При создании "конечных пользовательских интерфейсов" поможет именно и только словарь (или несколько словарей), или вообще любой механизм, считывающий из базы/создающий сам необходимые списки. Полагаться на то, что "внутренние" наборы данных приложения навечно останутся неизменными - по меньшей мере, глупомалопрофессионально... Особенно в приложениях M$ AndreTM
Сортировка и выборка уникальных - две разные задачи. Сливать их в одну не вижу смысла.
Пузырьковая сортировка - одна из самых медленных
И да и нет - механизм сочетающий в себе 2 механизма сразу. Кому-то может быть полезен, как готовое решение(особенно тем, кому сложно в вба соединить 2 механизма в один)
Таки да - Пузырьковая сортировка - одна из самых медленных Мне больше нравится от сюда:
[vba]
Код
Public Sub aQSort2(ByRef a() As Variant, ByVal n As Integer, ByRef low As Long, ByRef high As Long) Dim i As Long, j As Long, k As Long Dim m As Variant, wsp As Variant i = low j = high m = a(Round((i + j) \ 2), n) Do Until i > j Do While a(i, n) < m i = i + 1 Loop Do While a(j, n) > m j = j - 1 Loop If (i <= j) Then For k = LBound(a, 2) To UBound(a, 2) wsp = a(i, k) a(i, k) = a(j, k) a(j, k) = wsp Next k i = i + 1 j = j - 1 End If Loop If (low < j) Then aQSort2 a(), n, low, j If (i < high) Then aQSort2 a(), n, i, high End Sub
Сортировка и выборка уникальных - две разные задачи. Сливать их в одну не вижу смысла.
Пузырьковая сортировка - одна из самых медленных
И да и нет - механизм сочетающий в себе 2 механизма сразу. Кому-то может быть полезен, как готовое решение(особенно тем, кому сложно в вба соединить 2 механизма в один)
Таки да - Пузырьковая сортировка - одна из самых медленных Мне больше нравится от сюда:
[vba]
Код
Public Sub aQSort2(ByRef a() As Variant, ByVal n As Integer, ByRef low As Long, ByRef high As Long) Dim i As Long, j As Long, k As Long Dim m As Variant, wsp As Variant i = low j = high m = a(Round((i + j) \ 2), n) Do Until i > j Do While a(i, n) < m i = i + 1 Loop Do While a(j, n) > m j = j - 1 Loop If (i <= j) Then For k = LBound(a, 2) To UBound(a, 2) wsp = a(i, k) a(i, k) = a(j, k) a(j, k) = wsp Next k i = i + 1 j = j - 1 End If Loop If (low < j) Then aQSort2 a(), n, low, j If (i < high) Then aQSort2 a(), n, i, high End Sub
[/vba]
Танцы - супер . Очень наглядное объяснение SLAVICK
В свое время тоже делал сортировку уникальных на коллекциях методом вставки. В отличие от функции NoDups от ZVI из 6 сообщения поиск места вставки делал методом половинного деления, а не с поэлементным сравнением. Это дает хорошее ускорение. На 5000 элементах с 3116 унакальными значениями сортировка производится менее секунды (более чем в 20 раз быстрее чем у ZVI)
"Пузырек" Романа на этих же данных считал 3 минуты, при этом отсортировал не верно и допустил дубликаты
В свое время тоже делал сортировку уникальных на коллекциях методом вставки. В отличие от функции NoDups от ZVI из 6 сообщения поиск места вставки делал методом половинного деления, а не с поэлементным сравнением. Это дает хорошее ускорение. На 5000 элементах с 3116 унакальными значениями сортировка производится менее секунды (более чем в 20 раз быстрее чем у ZVI)
"Пузырек" Романа на этих же данных считал 3 минуты, при этом отсортировал не верно и допустил дубликатыMCH
МСН, а проблема с "ёжиками" и у Вас присутствует А все по той же причине, что и раньше. Эксель не знает алфавит (т.е. те кто писал программный код не знает)
ананас еж45 ел яблуко ёж ёжик
Но скорость Посмотрю у себя в архивах - где-то я тоже такое делал. Я тоже добавлял в коллекцию, а потом сортировал.
МСН, а проблема с "ёжиками" и у Вас присутствует А все по той же причине, что и раньше. Эксель не знает алфавит (т.е. те кто писал программный код не знает)
ананас еж45 ел яблуко ёж ёжик
Но скорость Посмотрю у себя в архивах - где-то я тоже такое делал. Я тоже добавлял в коллекцию, а потом сортировал.SLAVICK
Иногда все проще чем кажется с первого взгляда.
Сообщение отредактировал SLAVICK - Понедельник, 20.10.2014, 19:24
Про "ёжиков" не заморачивался, можно также как предлагалось менять "ё" на "е" или "еяяяя" при сравнении текстовых строк Пример во вложении, без особых доработок исходного файла
Про "ёжиков" не заморачивался, можно также как предлагалось менять "ё" на "е" или "еяяяя" при сравнении текстовых строк Пример во вложении, без особых доработок исходного файлаMCH