[英]filter out multiple criteria using excel vba
I have 8 variables in column A, 1,2,3,4,5 and A, B, C.我在 A、1、2、3、4、5 和 A、B、C 列中有 8 个变量。
My aim is to filter out A, B, C and display only 1-5.我的目标是过滤掉 A、B、C 并只显示 1-5。
I can do this using the following code:我可以使用以下代码执行此操作:
My_Range.AutoFilter Field:=1, Criteria1:=Array("1", "2", "3","4","5"), _
Operator:=xlFilterValues
But what the code does is it filters variables 1 to 5 and displays them.但是代码所做的是过滤变量 1 到 5 并显示它们。
I want to do the opposite, but yielding the same result, by filtering out A, B, C and showing variables 1 to 5我想做相反的事情,但通过过滤掉 A、B、C 并显示变量 1 到 5 来产生相同的结果
I tried this code:我试过这个代码:
My_Range.AutoFilter Field:=1, Criteria1:=Array("<>A", "<>B", "<>C"), _
Operator:=xlFilterValues
But it did not work.但它没有用。
Why cant I use this code ?为什么我不能使用这个代码?
It gives this error:它给出了这个错误:
Run time error 1004 autofilter method of range class failed运行时错误 1004 范围类的自动过滤方法失败
How can I perform this?我该如何执行此操作?
I think (from experimenting - MSDN is unhelpful here) that there is no direct way of doing this.我认为(从实验中 - MSDN 在这里没有帮助)没有直接的方法可以做到这一点。 Setting Criteria1
to an Array
is equivalent to using the tick boxes in the dropdown - as you say it will only filter a list based on items that match one of those in the array.将Criteria1
设置为Array
等效于使用下拉列表中的复选框 - 正如您所说,它只会根据与数组中的项目匹配的项目过滤列表。
Interestingly, if you have the literal values "<>A"
and "<>B"
in the list and filter on these the macro recorder comes up with有趣的是,如果列表中有文字值"<>A"
和"<>B"
并在这些值上进行过滤,宏记录器会给出
Range.AutoFilter Field:=1, Criteria1:="=<>A", Operator:=xlOr, Criteria2:="=<>B"
which works.哪个有效。 But if you then have the literal value "<>C"
as well and you filter for all three (using tick boxes) while recording a macro, the macro recorder replicates precisely your code which then fails with an error.但是,如果您随后也有文字值"<>C"
,并且您在录制宏时过滤了所有三个(使用勾选框),则宏录制器会精确复制您的代码,然后该代码会失败并出现错误。 I guess I'd call that a bug - there are filters you can do using the UI which you can't do with VBA.我想我会称其为错误 - 您可以使用 UI 执行过滤器,而 VBA 则无法执行这些过滤器。
Anyway, back to your problem.无论如何,回到你的问题。 It is possible to filter values not equal to some criteria, but only up to two values which doesn't work for you:可以过滤不等于某些条件的值,但最多只能过滤两个对您不起作用的值:
Range("$A$1:$A$9").AutoFilter Field:=1, Criteria1:="<>A", Criteria2:="<>B", Operator:=xlAnd
There are a couple of workarounds possible depending on the exact problem:根据确切的问题,有几种可能的解决方法:
=ISNUMBER(A2)
or =NOT(A2="A", A2="B", A2="C")
then filter on TRUE
在 B 列中使用带有公式的“辅助列”,然后对其进行过滤 - 例如=ISNUMBER(A2)
或=NOT(A2="A", A2="B", A2="C")
然后过滤TRUE
Criteria1:=">-65535"
(or a suitable number lower than any you expect) which will filter out non-numeric values - assuming this is what you want如果您无法添加列,请使用带有Criteria1:=">-65535"
(或低于您预期的合适数字)的自动过滤器,这将过滤掉非数字值 - 假设这是您想要的For example:例如:
Public Sub hideABCRows(rangeToFilter As Range)
Dim oCurrentCell As Range
On Error GoTo errHandler
Application.ScreenUpdating = False
For Each oCurrentCell In rangeToFilter.Cells
If oCurrentCell.Value = "A" Or oCurrentCell.Value = "B" Or oCurrentCell.Value = "C" Then
oCurrentCell.EntireRow.Hidden = True
End If
Next oCurrentCell
Application.ScreenUpdating = True
Exit Sub
errHandler:
Application.ScreenUpdating = True
End Sub
I don't have found any solution on Internet, so I have implemented one.我在互联网上没有找到任何解决方案,所以我实现了一个。
The Autofilter code with criteria is then带有标准的自动过滤器代码然后是
iColNumber = 1
Dim aFilterValueArray() As Variant
Call ConstructFilterValueArray(aFilterValueArray, iColNumber, Array("A", "B", "C"))
ActiveSheet.range(sRange).AutoFilter Field:=iColNumber _
, Criteria1:=aFilterValueArray _
, Operator:=xlFilterValues
In fact, the ConstructFilterValueArray() method (not function) get all distinct values that it found in a specific column and remove all values present in last argument.事实上,ConstructFilterValueArray() 方法(不是函数)获取它在特定列中找到的所有不同值,并删除最后一个参数中存在的所有值。
The VBA code of this method is这个方法的VBA代码是
'************************************************************
'* ConstructFilterValueArray()
'************************************************************
Sub ConstructFilterValueArray(a() As Variant, iCol As Integer, aRemoveArray As Variant)
Dim aValue As New Collection
Call GetDistinctColumnValue(aValue, iCol)
Call RemoveValueList(aValue, aRemoveArray)
Call CollectionToArray(a, aValue)
End Sub
'************************************************************
'* GetDistinctColumnValue()
'************************************************************
Sub GetDistinctColumnValue(ByRef aValue As Collection, iCol As Integer)
Dim sValue As String
iEmptyValueCount = 0
iLastRow = ActiveSheet.UsedRange.Rows.Count
Dim oSheet: Set oSheet = Sheets("X")
Sheets("Data")
.range(Cells(1, iCol), Cells(iLastRow, iCol)) _
.AdvancedFilter Action:=xlFilterCopy _
, CopyToRange:=oSheet.range("A1") _
, Unique:=True
iRow = 2
Do While True
sValue = Trim(oSheet.Cells(iRow, 1))
If sValue = "" Then
If iEmptyValueCount > 0 Then
Exit Do
End If
iEmptyValueCount = iEmptyValueCount + 1
End If
aValue.Add sValue
iRow = iRow + 1
Loop
End Sub
'************************************************************
'* RemoveValueList()
'************************************************************
Sub RemoveValueList(ByRef aValue As Collection, aRemoveArray As Variant)
For i = LBound(aRemoveArray) To UBound(aRemoveArray)
sValue = aRemoveArray(i)
iMax = aValue.Count
For j = iMax To 0 Step -1
If aValue(j) = sValue Then
aValue.Remove (j)
Exit For
End If
Next j
Next i
End Sub
'************************************************************
'* CollectionToArray()
'************************************************************
Sub CollectionToArray(a() As Variant, c As Collection)
iSize = c.Count - 1
ReDim a(iSize)
For i = 0 To iSize
a(i) = c.Item(i + 1)
Next
End Sub
This code can certainly be improved in returning an Array of String but working with Array in VBA is not easy.这段代码当然可以在返回字符串数组方面得到改进,但在 VBA 中使用数组并不容易。
CAUTION: this code work only if you define a sheet named X because CopyToRange parameter used in AdvancedFilter() need an Excel Range !注意:此代码仅在您定义名为 X 的工作表时才有效,因为 AdvancedFilter() 中使用的 CopyToRange 参数需要 Excel 范围!
It's a shame that Microfsoft doesn't have implemented this solution in adding simply a new enum as xlNotFilterValues !遗憾的是,微软没有通过简单地添加一个新的枚举作为 xlNotFilterValues 来实现这个解决方案! ... or xlRegexMatch ! ...或 xlRegexMatch !
Alternative using VBA's Filter function使用 VBA 的 Filter 函数的替代方法
As an innovative alternative to @schlebe 's recent answer, I tried to use the Filter
function integrated in VBA , which allows to filter out a given search string setting the third argument to False.作为@schlebe 最近答案的创新替代方案,我尝试使用集成在VBA 中的Filter
函数,它允许过滤掉给定的搜索字符串,将第三个参数设置为 False。 All "negative" search strings (eg A, B, C) are defined in an array.所有“否定”搜索字符串(例如 A、B、C)都定义在一个数组中。 I read the criteria in column A to a datafield array and basicly execute a subsequent filtering (A - C) to filter these items out.我将 A 列中的条件读取到数据字段数组中,并基本上执行后续过滤 (A - C) 以过滤掉这些项目。
Code代码
Sub FilterOut()
Dim ws As Worksheet
Dim rng As Range, i As Integer, n As Long, v As Variant
' 1) define strings to be filtered out in array
Dim a() ' declare as array
a = Array("A", "B", "C") ' << filter out values
' 2) define your sheetname and range (e.g. criteria in column A)
Set ws = ThisWorkbook.Worksheets("FilterOut")
n = ws.Range("A" & ws.Rows.Count).End(xlUp).row
Set rng = ws.Range("A2:A" & n)
' 3) hide complete range rows temporarily
rng.EntireRow.Hidden = True
' 4) set range to a variant 2-dim datafield array
v = rng
' 5) code array items by appending row numbers
For i = 1 To UBound(v): v(i, 1) = v(i, 1) & "#" & i + 1: Next i
' 6) transform to 1-dim array and FILTER OUT the first search string, e.g. "A"
v = Filter(Application.Transpose(Application.Index(v, 0, 1)), a(0), False, False)
' 7) filter out each subsequent search string, i.e. "B" and "C"
For i = 1 To UBound(a): v = Filter(v, a(i), False, False): Next i
' 8) get coded row numbers via split function and unhide valid rows
For i = LBound(v) To UBound(v)
ws.Range("A" & Split(v(i) & "#", "#")(1)).EntireRow.Hidden = False
Next i
End Sub
An option using AutoFilter使用自动筛选的选项
Option Explicit
Public Sub FilterOutMultiple()
Dim ws As Worksheet, filterOut As Variant, toHide As Range
Set ws = ActiveSheet
If Application.WorksheetFunction.CountA(ws.Cells) = 0 Then Exit Sub 'Empty sheet
filterOut = Split("A B C D E F G")
Application.ScreenUpdating = False
With ws.UsedRange.Columns("A")
If ws.FilterMode Then .AutoFilter
.AutoFilter Field:=1, Criteria1:=filterOut, Operator:=xlFilterValues
With .SpecialCells(xlCellTypeVisible)
If .CountLarge > 1 Then Set toHide = .Cells 'Remember unwanted (A, B, and C)
End With
.AutoFilter
If Not toHide Is Nothing Then
toHide.Rows.Hidden = True 'Hide unwanted (A, B, and C)
.Cells(1).Rows.Hidden = False 'Unhide header
End If
End With
Application.ScreenUpdating = True
End Sub
Here an option using a list written on some range, populating an array that will be fiiltered.这是一个使用在某个范围内写入的列表的选项,填充将被过滤的数组。 The information will be erased then the columns sorted.信息将被删除,然后对列进行排序。
Sub Filter_Out_Values()
'Automation to remove some codes from the list
Dim ws, ws1 As Worksheet
Dim myArray() As Variant
Dim x, lastrow As Long
Dim cell As Range
Set ws = Worksheets("List")
Set ws1 = Worksheets(8)
lastrow = ws.Cells(Application.Rows.Count, 1).End(xlUp).Row
'Go through the list of codes to exclude
For Each cell In ws.Range("A2:A" & lastrow)
If cell.Offset(0, 2).Value = "X" Then 'If the Code is associated with "X"
ReDim Preserve myArray(x) 'Initiate array
myArray(x) = CStr(cell.Value) 'Populate the array with the code
x = x + 1 'Increase array capacity
ReDim Preserve myArray(x) 'Redim array
End If
Next cell
lastrow = ws1.Cells(Application.Rows.Count, 1).End(xlUp).Row
ws1.Range("C2:C" & lastrow).AutoFilter field:=3, Criteria1:=myArray, Operator:=xlFilterValues
ws1.Range("A2:Z" & lastrow).SpecialCells(xlCellTypeVisible).ClearContents
ws1.Range("A2:Z" & lastrow).AutoFilter field:=3
'Sort columns
lastrow = ws1.Cells(Application.Rows.Count, 1).End(xlUp).Row
'Sort with 2 criteria
With ws1.Range("A1:Z" & lastrow)
.Resize(lastrow).Sort _
key1:=ws1.Columns("B"), order1:=xlAscending, DataOption1:=xlSortNormal, _
key2:=ws1.Columns("D"), order1:=xlAscending, DataOption1:=xlSortNormal, _
Header:=xlYes, MatchCase:=False, Orientation:=xlTopToBottom, SortMethod:=xlPinYin
End With
End Sub
This works for me: This is a criteria over two fields/columns (9 and 10), this filters rows with values >0 on column 9 and rows with values 4, 7, and 8 on column 10. lastrow
is the number of rows on the data section.这对我有用:这是两个字段/列(9 和 10)的标准,这将过滤第 9 列值 > 0 的行和第 10 列值lastrow
和 8 的行。 lastrow
是行数在数据部分。
ActiveSheet.Range("$A$1:$O$" & lastrow).AutoFilter Field:=9, Criteria1:=">0", Operator:=xlAnd
ActiveSheet.Range("$A$1:$O$" & lastrow).AutoFilter Field:=10, Criteria1:=Arr("4","7","8"), Operator:=xlFilterValues
Please check this one for filtering out values in a range.请检查这个以过滤出范围内的值。 It works有用
Selection.AutoFilter field:=33, Criteria1:="<>Array(IN1R,IN2R,INDA)", Operator:=xlFilterValues Selection.AutoFilter field:=33, Criteria1:="<>Array(IN1R,IN2R,INDA)", Operator:=xlFilterValues
Actually the above code did not work.实际上上面的代码不起作用。 Hence I given a loop to hide the entire row whenever the active cell had the value that I am searching for.因此,只要活动单元格具有我正在搜索的值,我就会给出一个循环来隐藏整行。
For each cell in selection If cell.value = “IN1R” or cell.value = “INR2” or cell.value = “INDA” then对于选择中的每个单元格 如果 cell.value = “IN1R” 或 cell.value = “INR2” 或 cell.value = “INDA” 然后
Else
Activecell.Entirerow.Hidden = True
End if
Next下一个
I have 8 variables in column A, 1,2,3,4,5 and A, B, C.我在A,1、2、3、4、5列和A,B,C中有8个变量。
My aim is to filter out A, B, C and display only 1-5.我的目的是过滤掉A,B,C并仅显示1-5。
I can do this using the following code:我可以使用以下代码执行此操作:
My_Range.AutoFilter Field:=1, Criteria1:=Array("1", "2", "3","4","5"), _
Operator:=xlFilterValues
But what the code does is it filters variables 1 to 5 and displays them.但是代码的作用是过滤变量1到5并显示它们。
I want to do the opposite, but yielding the same result, by filtering out A, B, C and showing variables 1 to 5我想做相反的事情,但通过滤除A,B,C并显示变量1至5产生相同的结果
I tried this code:我尝试了这段代码:
My_Range.AutoFilter Field:=1, Criteria1:=Array("<>A", "<>B", "<>C"), _
Operator:=xlFilterValues
But it did not work.但这没有用。
Why cant I use this code ?为什么我不能使用此代码?
It gives this error:它给出了这个错误:
Run time error 1004 autofilter method of range class failed范围类别的执行阶段错误1004自动筛选方法失败
How can I perform this?我该如何执行呢?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.