Макрос NoDups_in_Range производит подсчёт уникальных значений в видимых ячейках задаваемого в диалоге диапазона. Скрытые ячейки (автофильтром, шириной/высотой, группировкой) пропускаются. Если диапазон для подсчёта не задан, то значения считаются в выбранном диапазоне (Selection). При необходимости возможен вывод списка уникальных значений в задаваемый в диалоге диапазон.
Макрос NoDups_in_Range производит подсчёт уникальных значений в видимых ячейках задаваемого в диалоге диапазона. Скрытые ячейки (автофильтром, шириной/высотой, группировкой) пропускаются. Если диапазон для подсчёта не задан, то значения считаются в выбранном диапазоне (Selection). При необходимости возможен вывод списка уникальных значений в задаваемый в диалоге диапазон.Alex_ST
Разбирался тут в своих старых макросах и по ходу дела упростил и улучшил макрос NoDups_in_Range, выложенный здесь ранее. Теперь стало возможно рядом со столбцом уникальных значений выводить и количество их в указанном диапазоне.
Разбирался тут в своих старых макросах и по ходу дела упростил и улучшил макрос NoDups_in_Range, выложенный здесь ранее. Теперь стало возможно рядом со столбцом уникальных значений выводить и количество их в указанном диапазоне.Alex_ST
А потом, оказывается, ещё улучшил - без всяких UserForm вполне можно обойтись:[vba]
Код
Private Sub NoDups_in_Range() '--------------------------------------------------------------------------------------- ' Procedure : NoDups_in_Range ' Author : Alex_ST ' Purpose : вывод списка уникальных значений из ВИДИМЫХ ячеек задаваемого диапазона с возможностью подсчёта числа повторов '--------------------------------------------------------------------------------------- Dim Addr, rRng As Range, rCell As Range On Error Resume Next '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ' замена Application.InputBox("...", "...", Type:=8), не работающего на других листах и листах с УФ формулой Addr = Application.InputBox("Где брать список?", "Выбор диапазона данных", "=" & Selection.Address, Type:=0) If TypeName(Addr) = "Boolean" Then Exit Sub ' если нажали "Отмена", то Addr = False Addr = Range(Trim(Mid(Application.ConvertFormula(Addr, xlR1C1, xlA1, True), 2))).AddressLocal(0, 0, 1, 1) '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Set rRng = Intersect(Range(Addr).Parent.UsedRange.SpecialCells(xlCellTypeVisible), Range(Addr)): If Err Then Exit Sub With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare ' создаем временный словарь For Each rCell In rRng If Trim(rCell) <> "" Then .Item(Trim(rCell)) = .Item(Trim(rCell)) + 1 ' попытка записи значения по отсутствующему ключу добавит ключ в словарь Next If MsgBox("Видимые ячейки указанного диапазона содержат " & vbCrLf & .Count & " уникальных значений." & vbCrLf & _ "Вывести список на лист?", vbYesNo Or vbInformation, "Параметры списка") = vbNo Then Exit Sub '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ' замена Application.InputBox("...", "...", Type:=8), не работающего на других листах и листах с УФ формулой Addr = Application.InputBox("Куда выводить список?", "Выбор диапазона данных", "=" & Selection(1).Address, Type:=0) If TypeName(Addr) = "Boolean" Then Exit Sub ' если нажали "Отмена", то Addr = False Addr = Range(Trim(Mid(Application.ConvertFormula(Addr, xlR1C1, xlA1, True), 2))).AddressLocal(0, 0, 1, 1) '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Range(Range(Addr)(1, 1), Range(Addr)(.Count, 1)).Value = Application.WorksheetFunction.Transpose(.keys) Range(Addr).Parent.Activate ' перейти к листу, куда выводятся данные If MsgBox("Вывести количества в соседний столбец?", vbQuestion + vbYesNo, "Вывод данных") = vbYes Then Range(Range(Addr)(1, 2), Range(Addr)(.Count, 2)).NumberFormat = "General" Range(Range(Addr)(1, 2), Range(Addr)(.Count, 2)).Value = Application.WorksheetFunction.Transpose(.Items) Range(Range(Addr)(1, 1), Range(Addr)(.Count, 2)).Activate ' выделить диапазон выведенных данных Else Range(Range(Addr)(1, 1), Range(Addr)(.Count, 1)).Activate ' выделить диапазон выведенных данных End If End With End Sub
[/vba]
А потом, оказывается, ещё улучшил - без всяких UserForm вполне можно обойтись:[vba]
Код
Private Sub NoDups_in_Range() '--------------------------------------------------------------------------------------- ' Procedure : NoDups_in_Range ' Author : Alex_ST ' Purpose : вывод списка уникальных значений из ВИДИМЫХ ячеек задаваемого диапазона с возможностью подсчёта числа повторов '--------------------------------------------------------------------------------------- Dim Addr, rRng As Range, rCell As Range On Error Resume Next '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ' замена Application.InputBox("...", "...", Type:=8), не работающего на других листах и листах с УФ формулой Addr = Application.InputBox("Где брать список?", "Выбор диапазона данных", "=" & Selection.Address, Type:=0) If TypeName(Addr) = "Boolean" Then Exit Sub ' если нажали "Отмена", то Addr = False Addr = Range(Trim(Mid(Application.ConvertFormula(Addr, xlR1C1, xlA1, True), 2))).AddressLocal(0, 0, 1, 1) '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Set rRng = Intersect(Range(Addr).Parent.UsedRange.SpecialCells(xlCellTypeVisible), Range(Addr)): If Err Then Exit Sub With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare ' создаем временный словарь For Each rCell In rRng If Trim(rCell) <> "" Then .Item(Trim(rCell)) = .Item(Trim(rCell)) + 1 ' попытка записи значения по отсутствующему ключу добавит ключ в словарь Next If MsgBox("Видимые ячейки указанного диапазона содержат " & vbCrLf & .Count & " уникальных значений." & vbCrLf & _ "Вывести список на лист?", vbYesNo Or vbInformation, "Параметры списка") = vbNo Then Exit Sub '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ' замена Application.InputBox("...", "...", Type:=8), не работающего на других листах и листах с УФ формулой Addr = Application.InputBox("Куда выводить список?", "Выбор диапазона данных", "=" & Selection(1).Address, Type:=0) If TypeName(Addr) = "Boolean" Then Exit Sub ' если нажали "Отмена", то Addr = False Addr = Range(Trim(Mid(Application.ConvertFormula(Addr, xlR1C1, xlA1, True), 2))).AddressLocal(0, 0, 1, 1) '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Range(Range(Addr)(1, 1), Range(Addr)(.Count, 1)).Value = Application.WorksheetFunction.Transpose(.keys) Range(Addr).Parent.Activate ' перейти к листу, куда выводятся данные If MsgBox("Вывести количества в соседний столбец?", vbQuestion + vbYesNo, "Вывод данных") = vbYes Then Range(Range(Addr)(1, 2), Range(Addr)(.Count, 2)).NumberFormat = "General" Range(Range(Addr)(1, 2), Range(Addr)(.Count, 2)).Value = Application.WorksheetFunction.Transpose(.Items) Range(Range(Addr)(1, 1), Range(Addr)(.Count, 2)).Activate ' выделить диапазон выведенных данных Else Range(Range(Addr)(1, 1), Range(Addr)(.Count, 1)).Activate ' выделить диапазон выведенных данных End If End With End Sub
Алексей, добрый вечер. Использую Вашу очень полезную разработку, но вот столкнулся ситуацией где нужно диапазоны сделать по умолчанию, другими словами, ответить на все заданные в ЮзерФормс вопросы так:
Где брать данные?: Отгрузка!$F:$F Вывести список на лист?: ДА Куда выводить список?: Распределение!$A$2 Вывести количества в соседний столбец?: НЕТ
Можете сказать где и что указать в коде или подправить код по мою ситуацию? Заранее благодарен.
Просто нужно чтоб это выполнялось без лишних вопросов в одном документе по нажатию кнопки.
Алексей, добрый вечер. Использую Вашу очень полезную разработку, но вот столкнулся ситуацией где нужно диапазоны сделать по умолчанию, другими словами, ответить на все заданные в ЮзерФормс вопросы так:
Где брать данные?: Отгрузка!$F:$F Вывести список на лист?: ДА Куда выводить список?: Распределение!$A$2 Вывести количества в соседний столбец?: НЕТ
Можете сказать где и что указать в коде или подправить код по мою ситуацию? Заранее благодарен.
Просто нужно чтоб это выполнялось без лишних вопросов в одном документе по нажатию кнопки.DJ_Marker_MC
Завал на работе... Но раз уж обещал, то ловите (предупреждаю: не тестировал, некогда). Вариант 1: прямо в коде прописаны требуемые Вам адреса:
[vba]
Code
Sub NoDups_in_Range_Simple() Dim AddrIn$: AddrIn = "Отгрузка!$F:$F" Dim AddrOut$: AddrOut = "Распределение!$A$2" '--------------------------------------- Dim ShIn$: ShIn = Split(AddrIn, "!")(0): AddrIn = Split(AddrIn, "!")(1) Dim ShOut$: ShOut = Split(AddrOut, "!")(0): AddrOut = Split(AddrOut, "!")(1) Dim rRng As Range, rCell As Range On Error Resume Next Set rRng = Intersect(Sheets(ShIn).UsedRange.SpecialCells(xlCellTypeVisible), Sheets(ShIn).Range(AddrIn)): If Err Then Exit Sub With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare For Each rCell In rRng If Trim(rCell) <> "" Then .Item(Trim(rCell)) = .Item(Trim(rCell)) + 1 Next Sheets(ShOut).Activate ' перейти к листу, куда выводятся данные Range(AddrOut).Resize(.Count).Value = Application.WorksheetFunction.Transpose(.keys) End With End Sub
[/vba]
Недостаток: если Вы переименуете листы, вставите или удалите столбцы или строки выше или левее диапазонов ввода-вывода, то работать будет не правильно Вариант 2 : диапазоны ввода-вывода задаются именованными диапазонами "RangeIn" и "CellOut" соответственно:
[vba]
Code
Sub NoDups_in_Range_Simple_Plus() Dim sNameIn$: sNameIn = "RangeIn" ' имя диапазона, откуда берутся входные данные Dim sNameOut$: sNameOut = "CellOut" ' имя ячейки (диапазона), куда выводить результат '=========================================== Dim ShIn As Worksheet: Set ShIn = ThisWorkbook.Names(sNameIn).RefersToRange.Parent Dim AddrIn$: AddrIn = Split(ThisWorkbook.Names(sNameIn).Value, "!")(1) Dim ShOut As Worksheet: Set ShOut = ThisWorkbook.Names(sNameOut).RefersToRange.Parent Dim AddrOut$: AddrOut = Split(ThisWorkbook.Names(sNameOut).Value, "!")(1) '--------------------------------------- Dim rRng As Range, rCell As Range On Error Resume Next Set rRng = Intersect(ShIn.UsedRange.SpecialCells(xlCellTypeVisible), ShIn.Range(AddrIn)): If Err Then Exit Sub With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare For Each rCell In rRng If Trim(rCell) <> "" Then .Item(Trim(rCell)) = .Item(Trim(rCell)) + 1 Next ShOut.Activate ' перейти к листу, куда выводятся данные Range(AddrOut).Resize(.Count).Value = Application.WorksheetFunction.Transpose(.keys) End With End Sub
[/vba]
Здесь можно свободно работать с листами, строками и столбцами книги (естественно, кроме удаления диапазонов ввода-вывода)
Завал на работе... Но раз уж обещал, то ловите (предупреждаю: не тестировал, некогда). Вариант 1: прямо в коде прописаны требуемые Вам адреса:
[vba]
Code
Sub NoDups_in_Range_Simple() Dim AddrIn$: AddrIn = "Отгрузка!$F:$F" Dim AddrOut$: AddrOut = "Распределение!$A$2" '--------------------------------------- Dim ShIn$: ShIn = Split(AddrIn, "!")(0): AddrIn = Split(AddrIn, "!")(1) Dim ShOut$: ShOut = Split(AddrOut, "!")(0): AddrOut = Split(AddrOut, "!")(1) Dim rRng As Range, rCell As Range On Error Resume Next Set rRng = Intersect(Sheets(ShIn).UsedRange.SpecialCells(xlCellTypeVisible), Sheets(ShIn).Range(AddrIn)): If Err Then Exit Sub With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare For Each rCell In rRng If Trim(rCell) <> "" Then .Item(Trim(rCell)) = .Item(Trim(rCell)) + 1 Next Sheets(ShOut).Activate ' перейти к листу, куда выводятся данные Range(AddrOut).Resize(.Count).Value = Application.WorksheetFunction.Transpose(.keys) End With End Sub
[/vba]
Недостаток: если Вы переименуете листы, вставите или удалите столбцы или строки выше или левее диапазонов ввода-вывода, то работать будет не правильно Вариант 2 : диапазоны ввода-вывода задаются именованными диапазонами "RangeIn" и "CellOut" соответственно:
[vba]
Code
Sub NoDups_in_Range_Simple_Plus() Dim sNameIn$: sNameIn = "RangeIn" ' имя диапазона, откуда берутся входные данные Dim sNameOut$: sNameOut = "CellOut" ' имя ячейки (диапазона), куда выводить результат '=========================================== Dim ShIn As Worksheet: Set ShIn = ThisWorkbook.Names(sNameIn).RefersToRange.Parent Dim AddrIn$: AddrIn = Split(ThisWorkbook.Names(sNameIn).Value, "!")(1) Dim ShOut As Worksheet: Set ShOut = ThisWorkbook.Names(sNameOut).RefersToRange.Parent Dim AddrOut$: AddrOut = Split(ThisWorkbook.Names(sNameOut).Value, "!")(1) '--------------------------------------- Dim rRng As Range, rCell As Range On Error Resume Next Set rRng = Intersect(ShIn.UsedRange.SpecialCells(xlCellTypeVisible), ShIn.Range(AddrIn)): If Err Then Exit Sub With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare For Each rCell In rRng If Trim(rCell) <> "" Then .Item(Trim(rCell)) = .Item(Trim(rCell)) + 1 Next ShOut.Activate ' перейти к листу, куда выводятся данные Range(AddrOut).Resize(.Count).Value = Application.WorksheetFunction.Transpose(.keys) End With End Sub
[/vba]
Здесь можно свободно работать с листами, строками и столбцами книги (естественно, кроме удаления диапазонов ввода-вывода)Alex_ST
С уважением, Алексей MS Excel 2003 - the best!!!
Сообщение отредактировал Alex_ST - Четверг, 20.09.2012, 13:31
Дата: Воскресенье, 06.04.2014, 01:29 |
Сообщение № 10
Группа: Гости
Alex_ST, скажите пож-та, а как нужно видоизменить код, чтобы выявлялись несколько диапазонов и чтобы результат также выводился в разные места. Второй вариант с именованными диапазонами. мне больше подходит.
Alex_ST, скажите пож-та, а как нужно видоизменить код, чтобы выявлялись несколько диапазонов и чтобы результат также выводился в разные места. Второй вариант с именованными диапазонами. мне больше подходит.Сержик
Завал на работе у меня стал практически перманентным и отвлечься на посторонние программы там некогда, а дома я занимаюсь домашними делами (а уж их-то всегда выше крыши ) Поэтому, к сожалению, готовый код написать для Вас я не смогу. Но вообще-то проблема для тех, кто хоть чуть-чуть умеет писать процедуры VBA, совсем не большая: 1. Подпилите мой код так, чтобы ему диапазоны ввода-вывода задавались как параметры 2. Сделайте процедуру с циклом по Вашим именам диапазонов ввода-вывода, запускающую модернизированный код с передачей ему параметров
А уж как называть диапазоны и как их на основании придуманного Вами признака выделять их из всех имён книги - это уж Вам лично и карты в руки. Никто это за Вас без примера придумать не сможет.
Завал на работе у меня стал практически перманентным и отвлечься на посторонние программы там некогда, а дома я занимаюсь домашними делами (а уж их-то всегда выше крыши ) Поэтому, к сожалению, готовый код написать для Вас я не смогу. Но вообще-то проблема для тех, кто хоть чуть-чуть умеет писать процедуры VBA, совсем не большая: 1. Подпилите мой код так, чтобы ему диапазоны ввода-вывода задавались как параметры 2. Сделайте процедуру с циклом по Вашим именам диапазонов ввода-вывода, запускающую модернизированный код с передачей ему параметров
А уж как называть диапазоны и как их на основании придуманного Вами признака выделять их из всех имён книги - это уж Вам лично и карты в руки. Никто это за Вас без примера придумать не сможет.Alex_ST
Alex_ST, спасибо за отличный макрос! А есть возможность сделать вывод уникальных значений по нескольким столбцам с последующей выдачей значений из одного столбца. Например: В столбцах А,B,C, соответственно:
Alex_ST, спасибо за отличный макрос! А есть возможность сделать вывод уникальных значений по нескольким столбцам с последующей выдачей значений из одного столбца. Например: В столбцах А,B,C, соответственно:
Arseniy_K, придерживайтесь правил, пожалуйста. Если Вам нужна какая-то доработка выложенного УНИВЕРСАЛЬНОГО макроса под Ваши СПЕЦИФИЧЕСКИЕ нужды, то вопрос нужно задавать не в Готовых решениях, а в Вопросах по VBA. Но в любом случае - нужен Ваш пример - таблица Excel с образцом исходных данных и желаемым результатом их обработки, а не текстовое описание. А из Вашего описания, к стати, следует, что никакой доработки моего макроса не требуется просто выделяете данные в столбце А, запускаете его и указываете, куда Вам нужно выводить результаты - уникальные значения, а рядом с ними - количество повторов.
Arseniy_K, придерживайтесь правил, пожалуйста. Если Вам нужна какая-то доработка выложенного УНИВЕРСАЛЬНОГО макроса под Ваши СПЕЦИФИЧЕСКИЕ нужды, то вопрос нужно задавать не в Готовых решениях, а в Вопросах по VBA. Но в любом случае - нужен Ваш пример - таблица Excel с образцом исходных данных и желаемым результатом их обработки, а не текстовое описание. А из Вашего описания, к стати, следует, что никакой доработки моего макроса не требуется просто выделяете данные в столбце А, запускаете его и указываете, куда Вам нужно выводить результаты - уникальные значения, а рядом с ними - количество повторов. Alex_ST