Excel: исключения автофильтра с более чем двумя критериями - PullRequest
0 голосов
/ 09 сентября 2018

Это вопрос, который иногда возникает (например: см. здесь и здесь ), и почти всегда ему предлагаются решения, основанные на некотором цикле (с самим AutoFilter() или массивами)

По какой-то причине разработчики Excel ограничили AutoFilter критериев пользовательских массивов максимум двумя, поэтому следующее не будет работать:

    Dim filterNotCriteria = Array("<>A","<>B","<>C")

    someRange.AutoFilter field:=1, Criteria1:=filterNotCriteria, Operator:=xlFilterValues

Хотя я думаю, что было бы действительно полезно иметь эту AutoFilter() функциональность полностью доступной, как и для ее "нестандартного" аналога

Итак, ожидая, пока разработчики Excel добавят его (или исправят, так как это выглядит для меня скорее как ошибка), я бы начал этот вопрос как общедоступный опрос (не уверен, что это правильный путь) в что может быть лучшим исправлением VBA как с точки зрения производительности, так и с точки зрения удобства использования

И я добавляю первый ответ, чтобы начать вращение шара

1 Ответ

0 голосов
/ 09 сентября 2018

Моей первой мыслью было придерживаться AutoFilter(), чтобы извлечь выгоду из его производительности

Используя некоторую обратную мысль , шаги будут:

  • фильтр с соответствующими НЕ (критериями)

    чтобы получить то, что нам не нужно

  • скрыть строки, которые у нас есть и которые нам не нужны

  • оставить с нужными строками

следующим образом:

Option Explicit

Function AutoFilterNot(rngToFilter As Range, fieldToFilterOn As Long, filterNotCriteria As Variant) As Range
    Dim notRng As Range ' helper range variable

    With rngToFilter ' reference wanted range to filter, headers row included
        .AutoFilter field:=fieldToFilterOn, Criteria1:=filterNotCriteria, Operator:=xlFilterValues ' filter on "not wanted" values
        If Application.Subtotal(103, .Resize(, 1)) > 1 Then ' if any filtered cell other than header row
            Set notRng = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) ' temporarily set 'myRng' to "not wanted" rows
            .Parent.AutoFilterMode = False ' remove filters and show all rows
            notRng.EntireRow.Hidden = True ' leave "wanted" rows only visible

            Set AutoFilterNot = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible) ' get referenced range "wanted" rows

            .EntireRow.Hidden = False ' unhide all referenced range rows
        Else
            .Parent.AutoFilterMode = False ' remove filters
        End If
    End With
End Function

и это можно использовать в некотором «основном» коде следующим образом:

Dim filteredRng As Range

Set filteredRng = AutoFilterNot(Range("A1:C200"), 2, Array("B102", "A107"))
...