Автофильтр Excel VBA все, кроме трех

В продолжающейся саге моего анализа данных (Первый вопрос), я хочу удалить все строки, в которых отделы (поле 7) не равны 101, 102 или 103 (имена были изменены, чтобы защитить невиновных). В данных около сотни отделов, поэтому использование Criteria1:=Array("104", "105", "106", и т. Д. Нецелесообразно.

Я бы хотел сделать что-то вроде этого:

myrange.AutoFilter Field:=7, Criteria1:="<>101", Operator:=xlOr, _
    Criteria2:="<>102", Operator:=xlOr, Criteria3:="<>103"

но Excel не распознает более 2 критериев. Я мог бы добавить вспомогательный столбец и запустить макрос по каждой строке (если 101, 102 или 103, тогда значение = Да), отфильтровать да и удалить все, что осталось, но я сохраняю это как последнее прибегнуть.

Есть ли способ, чтобы критерий автофильтрации не был равен массиву? Что-то вроде:

myrange.AutoFilter Field:=7, Criteria1:="<>" & Array("101", "102", "103")

person Kes Perron    schedule 21.10.2013    source источник


Ответы (4)


Помните, что цель состоит в том, чтобы удалить несовпадающие строки; Автофильтр - это лишь один из инструментов, помогающих достичь цели. Если автофильтр вам не подходит, выберите другой метод. Рассмотреть возможность:

Sub AllBut()
    Dim rTable As Range, r As Range
    Dim rDelete As Range
    Set rTable = Selection
    Set rDelete = Nothing
    For Each r In rTable.Columns(7).Cells
        v = r.Value
        If v <> "101" And v <> "102" And v <> "103" Then
            If rDelete Is Nothing Then
                Set rDelete = r
            Else
                Set rDelete = Union(r, rDelete)
            End If
        End If
    Next

    If Not rDelete Is Nothing Then rDelete.EntireRow.Delete
End Sub

Здесь мы выбираем блок данных для обработки (не включая строку заголовка). Макрос просматривает столбец № 7 этого блока и удаляет все строки, не соответствующие критериям.

Все, что останется, - это модели 101, 102 и 103.

person Gary's Student    schedule 21.10.2013
comment
@ garys-student Мне тяжело следить за этим. Я предполагаю, что строка 6 означает для каждой ячейки в столбце G моих данных, но я не уверен, как это происходит, поскольку диапазон для r никогда не устанавливается. Кроме того, я не знаком с функцией Union. Правильно ли я предполагаю, что он добавляет текущую ячейку в диапазон rDelete? - person Kes Perron; 29.10.2013
comment
Кроме того, не нужно ли декларировать v? - person Kes Perron; 29.10.2013
comment
@SMPerron: Вы правы в своих предположениях, в цикле For r устанавливается каждый раз при прохождении цикла, и его не нужно устанавливать явно. Если v не затемнен, предполагается, что это вариант. Откройте новую, новую книгу, поместите в нее временные данные и попробуйте макрос. Если что-то пойдет не так, ваши настоящие данные не будут повреждены ..... Удачи! - person Gary's Student; 29.10.2013

Поскольку речь шла о методе автофильтрации, я предлагаю вверх по этому методу с использованием объекта Scripting.Dictionary для имитации процедура, которая использовалась бы, если бы это выполнялось на листе вручную.

На рабочем листе пользователь применил бы Автофильтр, а затем использовал бы выпадающий столбец G, чтобы «отключить» значения 101, 102 и 103. То, что осталось, будет удалено. В VBA мы можем получить весь столбец G и заполнить объект словаря значениями, отличными от 101, 102 или 103, и использовать это в качестве критерия для операции фильтрации.

Sub filterNotThree()
    Dim d As Long, dDELs As Object, vVALs As Variant

    Set dDELs = CreateObject("Scripting.Dictionary")

    With Worksheets("Sheet6")
        If .AutoFilterMode Then .AutoFilterMode = False
        With .Cells(1, 1).CurrentRegion
            'grab all of column G (minus the header) into a variant array
            vVALs = .Resize(.Rows.Count - 1, 1).Offset(1, 6).Value2

            'populate the dictionary object with the values that are NOT 101, 102, or 103
            For d = LBound(vVALs, 1) To UBound(vVALs, 1)
                Select Case vVALs(d, 1)
                    Case 101, 102, 103
                        'do not add
                    Case Else
                        'not a match, add it to the delete list
                        'the AutoFilter criteria needs to be text
                        ' so we set the Keys as text and the Items as numbers
                        dDELs.Item(CStr(vVALs(d, 1))) = vVALs(d, 1)
                End Select
            Next d

            'check to make sure there is something to filter on
            If CBool(dDELs.Count) Then
                'filter on the dictionary keys
                .AutoFilter field:=7, Criteria1:=dDELs.keys, Operator:=xlFilterValues

                'delete the visible rows (there has to be some)
                .Resize(.Rows.Count - 1, .Columns.Count).Offset(1, 0).EntireRow.Delete
            End If

        End With
        If .AutoFilterMode Then .AutoFilterMode = False
    End With

    dDELs.RemoveAll: Set dDELs = Nothing
End Sub

filterNotThree_before
Данные до подпроцедуры filterNotThree

filterNotThree_after
Данные после подпроцедуры filterNotThree

person Community    schedule 31.01.2016

Я делал что-то подобное, но для двух полей, и этот синтаксис у меня работал:

myrange.AutoFilter Field:=7, Criteria1:="<>101", Operator:=xlAnd, Criteria2:="<>102", Operator:=xlAnd

Надеюсь, это поможет.

person AniSetchi    schedule 03.02.2016

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

myrange.AutoFilter Field:=7, Criteria1:=Array("<>101", "<>102", "<>103"), Operator:=xlFilterValues
person Kristi Johnson    schedule 07.04.2021