Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

[Excel] Как выбрать из массива Excel уникальные элементы?

40K
07 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Естественно желательно это сделать средствами/функциями Excel, ибо макросы VBA дольше.
Есть ли вообще решение этой задачи без использования VBA?
275
07 апреля 2009 года
pashulka
985 / / 19.09.2004
Выделите необходимый диапазон, включая заголовок(шапку), после чего в меню Данные выберите пункт Фильтр и команду Расширенный фильтр. Затем, в появившемся стандартном диалоговом окне установите "флажок" напротив Только уникальные записи и OK. Полученные таким образом данные можно, например, скопировать в другой рабочий лист (если копировать нужно в этот же рабочий лист, то достаточно установить переключатель Скопировать результат в другое место и с помощью текстового поля Поместить результат в диапазон выбрать/указать ячейку, с которой должен начинаться список уникальных значений)

Кстати, используя VBA также можно мучить расширенный фильтр, причём, это не занимает много времени :

 
Код:
Worksheets("Лист1").Range("A1:C100").AdvancedFilter _
Action:=xlFilterCopy, CopyToRange:=Worksheets.Add.Range("A1"), Unique:=True


 
Код:
Worksheets("Лист1").Range("A1:C100").AdvancedFilter _
xlFilterCopy, , Worksheets.Add.Range("A1"), True
40K
08 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Спасибо
40K
10 апреля 2009 года
JJJJoke
24 / / 18.03.2009
В описании расширенного фильтра указано, что результат отбора по фильтру можно вставлять в тот же лист, соответственно та же книга. В приведенном примере можно добавить результа на новый лист, либо другой
 
Код:
Worksheets("name1").Columns("A:B").AdvancedFilter _
   xlFilterCopy, , Worksheets("name2").Range("A1"), True

однако код, где dest_book - другая книга выдает ошибку
 
Код:
source_book.Worksheets("name1").Columns("A:B").AdvancedFilter _
   xlFilterCopy, , dest_book.Worksheets("name2").Range("A1"), True

правда и это можно обойти, вставив ссылки на сами листы
 
Код:
source_sheet.Columns("A:B").AdvancedFilter _
   xlFilterCopy, , dest_sheet.Range("A1"), True

Отсюда и возникают вопросы, правильно ли будет работать фильтр в последнем примере? Почему изначально Excel не разрешает копировать не то, что в другую книгу, а даже на другой лист, а в VBA эти ограничения можно обойти? Зачему нужны такие ограничения?
275
12 апреля 2009 года
pashulka
985 / / 19.09.2004
То, что результат можно копировать в ячейки другого рабочего листа, довольно наглядно показано в моём первом примере, более того, этот лист может находиться в другой рабочей книге и никаких ухищрений, при этом, использовать не нужно (проверено многолетним личным опытом) и результат копирования будет более чем корректен.

 
Код:
Workbooks("Книга1.xls").Worksheets("Лист1").Range("A:B").AdvancedFilter _
xlFilterCopy, , Workbooks("Книга2.xls").Worksheets("Лист2").Range("A1"), True


 
Код:
Dim iSourceWB As Workbook, iDestinationWB As Workbook

Set iSourceWB = Workbooks("Книга1.xls")
Set iDestinationWB = Workbooks("Книга2.xls")
   
iSourceWB.Worksheets("Лист1").[A:B].AdvancedFilter _
2, , iDestinationWB.Worksheets("Лист2").[A1], True


А что касается вопроса, связанного с непрограммным использованием расширенного фильтра, то его, конечно же, нужно адресовать непосредственно разработчикам.
40K
13 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Хм, а у меня ошибку такой код выдал. Причем не VBA, а excel. Ну да ладно, может действительно что-то неправильно сделал.
Спасибо.
40K
13 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Теперь такая проблема возникла:
если фильтруемые ячейки - значения (например числа, то все работает), если же фильтруемые ячейки - формулы, то фильтруются сами формулы, а не значения.
Как отфильтровать значения с помощью расширенного фильтра, если я фильтрую столбец, который получен с помощью формул?
275
13 апреля 2009 года
pashulka
985 / / 19.09.2004
Всё правильно, используя стандартное диаловое окно действительно нельзя поместить результат фильтрации в ячейки другого рабочего листа (о чём я, кстати, также упоминал в первом сообщении), однако, программно осуществить желаемое можно, причём без дополнительных телодвижений.

Что же касается копирования формул, то это абсолютно нормально, к слову сказать, тоже самое произойдёт и при обычном копировании, типа, CTRL+C и CTRL+V, а бороться с этим безобразием можно использовав, к примеру, фильтрацию на месте + копирование и специальную вставку значений :

 
Код:
With Application.Range("[Книга1.xls]Лист1!A:B")
     .AdvancedFilter xlFilterInPlace, , , True
     .Copy
      Application.Range("[Книга2.xls]Лист2!A1").PasteSpecial xlValues
     .Worksheet.ShowAllData
End With

'Если имя книги/листа может содержать, например, пробел, то _
Application.Range("'[Книга1.xls]Лист 1'!A:B")


или

 
Код:
Application.ScreenUpdating = False

With Workbooks("Книга1.xls").Worksheets("Лист1").Range("A:B")
     .AdvancedFilter xlFilterInPlace, , , True
     .Copy
      Workbooks("Книга2.xls").Worksheets("Лист2").Range("A1").PasteSpecial xlValues
     .Parent.ShowAllData
End With

Application.ScreenUpdating = True
40K
13 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Спасибо за оперативность.
Все таки есть различия между vba и excel в плане пользования этого расширенного фильтра: попробовал в excel на рабочем листе, так там по значениям, а не по формулам отфильтровал.
P.S.: Не учел
Цитата:
'Если имя книги/листа может содержать, например, пробел, то _
Application.Range("'[Книга1.xls]Лист 1'!A:B")

Вот и писал, что ошибка выдается когда ссылаешься по workbook.sheet("").

275
13 апреля 2009 года
pashulka
985 / / 19.09.2004
Уточнение : Если фильтровать на месте, то копироваться будут формулы, если же сразу копировать в другие ячейки, то в результате получим значения. Прошу прощения, что ввёл Вас в заблуждение, видимо года уже берут своё.
40K
13 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Что то я совсем запутался.
В одном месте используется код

 
Код:
Set dstSht = ThisWorkbook.Worksheets("техн_инфо")
Set srcSht = srcFile.Worksheets(1)

srcSht.Range("A:AC").AdvancedFilter _
   xlFilterCopy, dstSht.Range("критерий"), dstSht.Range("результат"), False

Работает отлично.
Ниже в макросе используется следующий код
 
Код:
ThisWorkbook.Sheets("техн_инфо").[A:C].AdvancedFilter xlFilterCopy, , ThisWorkbook.Sheets("Свод").[A1], True

Не работает. Вместо результата в ячейке A1 присваивается имя "Извлечь" и все.
Как ни крутил, не могу найти ошибку. Уже и dstSht и srcSht занулил, думал как-нить может ссылки как-то пересекаются, не помогает. Даже не знаю, где искать ошибку. В этой одной строчке?
В чем может быть проблема?
275
13 апреля 2009 года
pashulka
985 / / 19.09.2004
В первом примере Вы фильтруете, только используя диапазон условий (в этом случае, кстати, значение аргумента Unique можно и не указывать, ибо оно по умолчанию False), а во втором случае Вы уже хотите получить список уникальных значений (см. пример)
40K
13 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Да, я это прекрасно понимаю. Вот только на мой взгляд, код написан правильно и тот, и второй (второй прям по Вашему шаблону, для уникальных записей), а компилятор так не считает. Первый код выполняется хорошо (хотя тоже рэнжу, куда выводятся значения фильтра автоматически присваивается имя Извлечь, а рэнжу критериев - Критерии). В принципе, так как фильтрация происходит, то на эти имена мне наплевать. С другой стороны вопрос, откуда все-таки они берутся?
Проблема в том, что я в упор не вижу ошибку во втором фагменте кода, когда хочу отобрать уже уникальные записи. Может устал.
Рыща по интернету, заметил несколько замечаний по-поводу расширенного фильтра, что могут ошибки возникать из-за минимальных изменений. Например, если к книге сделать общий доступ, то правильно работающий код до этого, перестает работать.
Вот и вопрос, как узнать, при каких условиях и каких параметрах работает расширенный фильтр? В мсдн я, по крайне мере, ничего не нашел полезного.
275
13 апреля 2009 года
pashulka
985 / / 19.09.2004
Имена создаёт сам Excel, видимо, для упрощения работы в т.ч. и с расширенным фильтром, ибо сказано в справке, цитирую

Цитата:
Совет. Если на листе существует диапазон с именем Критерии, то в поле Диапазон условий автоматически появится ссылка на этот диапазон.



Кстати, вместо База_данных, Критерии, Извлечь можно использовать DataBase, Criteria, Extract

Я тоже устал, но синтаксис правильный, более того, в моём примере он таки позволяет получить уникальные записи, возможно собака порылась в чём-то другом ... но в любом случае Вы можете попробовать использовать в качестве критерия отбора формулу, или посмотреть чем Вам может помочь Microsoft Query (если он, конечно, установлен), который также позволяет извлечь уникальные записи (Данные - Внешние данные)

С MSDN и справкой соревноваться не возьмусь, однако, замечу, что общая книга это вообще отдельный разговор и в оной есть много ограничений, в т.ч. и запрет на использование расширенного фильтра.

40K
14 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Ok, спасибо за дискуссию. Буду ковырятся дальше.
40K
14 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Обнаружил вот такую вещь:
1. Почти во всех Ваших примерах источник информации и назначение - две разные книги. Только в первом примере используется одна и таже книга, правда результат помещается во вновь добавляемый лист.

2. Первая часть моего кода работает с разными книгами, поэтому все и получается и фильтруется нормально. Вторая же часть кода должна фильтровать данные с одного листа и вставлять результат на другой лист той же книги. Вот здесь ничего и не происходит. Но если создать новую книгу и скопировать туда данные, которые хочу фильтровать, то код начинает работать.

Отсюда вопрос, в чем суть проблемы и можно ли это обойти, не создавая временную книгу?

Проверил код первого примера, где добавляется страница - такой же результат. Вот код:

ThisWorkbook.Worksheets("техн_инфо").Range("A:I").AdvancedFilter _
xlFilterCopy, , ThisWorkbook.Sheets.Add.Range("A1"), True

То же самое. Фильтрации не происходит. В последнем случае просто добавляются подписи данных (первая строчка данных) на новый лист, сами данные не фильтруются и не вставляются.
У Вас действительно работает расширенный фильтр при копировании внутри одной книги?
У меня это не заработало!
40K
14 апреля 2009 года
JJJJoke
24 / / 18.03.2009
Все разобрался наконец-то. Да, действительно можно использовать только один фильтр в рабочей книге. Это происходит из-за конфликта имен (уже упоминалось об использовании имен). Расширенный фильтр в ходе своей работы присваивает ячейкам критерия, ячейкам для результата имена (в рус.яз excel Критерии, Извлечь). Если эти имена не удалять, то второй расширенный фильтр, запущенный в ходе выполнения макроса результата не даст (если только не разные книги используются в качестве источника и назначения).
Отсюда решение:
Если Вы используете более одного расширенного фильтра, то нужно либо, чтобы источник данных и "приемник" скопированных данных находились в разных книгах, либо во время выполнения макроса удалять, появляющиеся после каждой "расширенной" фильтрации, имена Извлечь и Критерии.
Для второго варианта либо

ThisWorkBook.Names("Extract").Delete

либо

ThisWorkBook.Sheets("sheet_name").Names("Extract").Delete

Тоже самое и для Критерии ("Criteria")

P.S.: Я бы вообще рекомендовал после каждого использования расширенного фильтра затирать указанные имена, чтобы в дальнейшем не возникало лишних хлопот и проблем
275
14 апреля 2009 года
pashulka
985 / / 19.09.2004
[quote=JJJJoke]Почти во всех Ваших примерах источник информации и назначение - две разные книги. Только в первом примере используется одна и таже книга, правда результат помещается во вновь добавляемый лист.[/quote]

Отнюдь, не только в первом, но и последнем примере используется одна и таже рабочая книга, и если в первом примере результат действительно копируется в ячейки нового рабочего листа, то в последнем уже в ячейки рабочего листа с именем "Свод"

[quote=JJJJoke]У Вас действительно работает расширенный фильтр при копировании внутри одной книги? У меня это не заработало![/quote]

Естественно, иначе зачем бы я стал это предлагать и даже закачивать пример, более того, в XL97, XL2000 нет никаких конфликтов имён, расширенный фильтр можно применять в нескольких рабочих листах, удалять имена перед этим не нужно.

Кстати, если уж опять вспомнили имена, рекомендую более детально разобраться с об'ектом Name, ибо два вышеопубликованных варианта будут идентичны только в том случае, если речь идёт о имени уровня рабочей книги(глобальном), а в этом случае можно использовать ещё и следующий синтаксис :

 
Код:
[Extract].Delete


 
Код:
Evaluate("Extract").Delete
14K
19 апреля 2009 года
KlerK
10 / / 07.04.2006
А можно ли результат поместить сразу в Combobox?
275
19 апреля 2009 года
pashulka
985 / / 19.09.2004
К сожалению, сразу нельзя. Но можно, к примеру, скопировать данные в ячейки скрытого рабочего листа и связать ComboBox с этими ячейками, с помощью свойства RowSource(UserForm) / ListFillRange(Worksheet)
Если же наличие дополнительного рабочего листа нежелательно, то можно скопировать в ячейки новой рабочей книги, заполнить ComboBox, используя свойство List, и закрыть новую книгу без изменений. Естественно, все эти операции желательно скрыть, а посему Application.ScreenUpdating = False / True
14K
19 апреля 2009 года
KlerK
10 / / 07.04.2006
Спасибо, Павел. Если созданная книга с диапазоном уник.значений удаляется, значит лучше для заполнения ComboBox применить .AddItem.
275
19 апреля 2009 года
pashulka
985 / / 19.09.2004
Нет, лучше использовать именно свойство .List так оно позволяет заполнить ComboBox/ListBox без цикла
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог