1
ThisWorkbook.Sheets(1).Range("A1:AR1").AutoFilter Field:=27, _
Criteria1:=Array("<>DRCA", "<>DREX", "<>DRFU", "<>DRIN", _
"<>DRIR", "<>DRND", "<>DRPN", "<>DRPR", "<>DRRE", "<>DRUN", _
"<>REXC", "<>EXCD", "<>RFUR", "<>RINV", "<>RIRC", "<>RNDR", _
"<>RPNA", "<>RPRO", "<>RRET", "<>RUND", "<>RUNF", "<>EXC", "<>C"), _
Operator:=xlFilterValues

This is not returning correct filter data that I want. What I want is that if array doesn't find any <> value then skip it and check next.

How do I go about it?

Community
  • 1
  • 1
Dharmendra
  • 119
  • 1
  • 4
  • 8
  • Do you just want to filter using the xlOr operator? For example do you want to return rows where Field 27 is DRCA or DREX or DRFU or DRIN, etc.? – Excel Hero Sep 12 '15 at 15:32
  • See [This](http://stackoverflow.com/questions/19497659/excel-vba-autofilter-all-but-three) or [This](http://stackoverflow.com/questions/28575754/filter-out-multiple-criteria-using-excel-vba) – Siddharth Rout Sep 12 '15 at 15:36
  • Auto Filter imho requires at least 2 rows of data. I am not sure whether it is a correct approach. – skkakkar Sep 12 '15 at 15:37
  • There is one more method if you really want to use the autofilter. i.e use the "Inverse" of the autofilter. let me see if I can quickly create an example of what I mean by inverse – Siddharth Rout Sep 12 '15 at 15:38
  • Do you just want to filter using the xlOr operator? For example do you want to return rows where Field 27 is DRCA or DREX or DRFU or DRIN, etc.?------ I want rest value except these all value which are mentioned – Dharmendra Sep 12 '15 at 15:53

2 Answers2

4

Excel doesn't allow you to use the array like you want it in the Autofilter. But is there an alternative? Yes!

Logic If I ask you choose numbers between 0 and 10 including 0 and 10 but you cannot choose 0, 5, 8 and 10. So instead of filtering the numbers out and saying I don't want 0, 5, 8 and 10, you can say I want 1,2,3,4,6,7,9.

Similarly in your case we will not filter on the values we DON'T want. We will filter on values we WANT.

So HOW do we find that list and store it in an array?

  1. Find the last row in the relevant column.
  2. Store all records from that column in a unique collection
  3. Check which items in that collection are not in the "exclude" list and create an array.
  4. Filter the range on the values(array) you want! This way we will not have to filter on the values which we don't want.

Code (Tested in Excel 2013 with 50k records)

I have commented the code but if you still have any questions then feel free to ask :)

Dim OmitArray As Variant
Const deLim As String = "|"

Sub Sample()
    Dim Ws As Worksheet
    Dim lRow As Long, i As Long, n As Long, lCol As Long
    Dim Col As New Collection, itm
    Dim includeArray As Variant
    Dim rng As Range
    Dim tmpString As String

    '~~> This array has all the values that you want to ignore
    OmitArray = Array("DRCA", "DREX", "DRFU", "DRIN", "DRIR", "DRND", _
                "DRPN", "DRPR", "DRRE", "DRUN", "REXC", "EXCD", "RFUR", _
                "RINV", "RIRC", "RNDR", "RPNA", "RPRO", "RRET", "RUND", _
                "RUNF", "EXC", "C")

    '~~> This is the column where you want to filter out
    lCol = 27

    '~~> Change this to the relevant worksheet
    Set Ws = ThisWorkbook.Sheets("Sheet1")

    With Ws
        '~~> Find lastrow
        lRow = .Range("A" & .Rows.Count).End(xlUp).Row

        '~~> This is the range where the filter will be applied
        Set rng = .Range("A1:AR" & lRow)

        '~~> All all the values from col 27 to a unique collection
        For i = 2 To lRow
            On Error Resume Next
            Col.Add .Cells(i, lCol).Value, CStr(.Cells(i, 27).Value)
            On Error GoTo 0
        Next i

        '~~> Now loop though the collection and store the values in a string
        '~~> delimited with a delimiter which arenot present in the "OmitArray"
        For Each itm In Col
            If Not IsInArray(itm, OmitArray) Then
                If tmpString = "" Then
                    tmpString = itm
                Else
                    tmpString = tmpString & deLim & itm
                End If
            End If
        Next itm

        If tmpString <> "" Then
            '~~> Split the values based on the delimiter to create array
            includeArray = Split(tmpString, deLim)

            '~~> Remove any filters
            .AutoFilterMode = False

            '~~> Filter on the rest of the values
            With rng
              .AutoFilter Field:=lCol, Criteria1:=includeArray, Operator:=xlFilterValues
            End With
        End If
    End With
End Sub

'~~> Function to check if there is an item in the array
Function IsInArray(stringToBeFound As Variant, arr As Variant) As Boolean
    Dim bDimen As Byte, i As Long

    On Error Resume Next
    If IsError(UBound(arr, 2)) Then bDimen = 1 Else bDimen = 2
    On Error GoTo 0

    Select Case bDimen
    Case 1
        On Error Resume Next
        IsInArray = Application.Match(stringToBeFound, arr, 0)
        On Error GoTo 0
    Case 2
        For i = 1 To UBound(arr, 2)
            On Error Resume Next
            IsInArray = Application.Match(stringToBeFound, Application.Index(arr, , i), 0)
            On Error GoTo 0
            If IsInArray = True Then Exit For
        Next
    End Select
End Function
Siddharth Rout
  • 147,039
  • 17
  • 206
  • 250
  • It has been my experience that you need to wrap a variant array in brackets in order that the [Range.AutoFill method](https://msdn.microsoft.com/en-us/library/office/ff195345.aspx) properly perceives it as an array. e.g. `Criteria1:=(includeArray)` –  Sep 12 '15 at 23:13
  • Ignore my last comment. Apparently the aberrant behavior I described has been fixed. `Criteria1:=includeArray` works just fine. –  Sep 13 '15 at 01:02
2

You cannot use the AutoFilter from VBA to explicitly exclude more than two values for a given field. Instead you need to specify the values you want included.

But you do not need to use the AutoFilter to hide the rows containing specific values.

Here is a short routine that will work in your case. You can manage which rows to hide by editing the first line:

Public Sub Demo()
    Const HIDE = ".DRCA.DREX.DRFU.DRIN.DRIR.DRND.DRPN.DRPR.DRRE.DRUN.REXC.EXCD.RFUR.RINV.RIRC.RNDR.RPNA.RPRO.RRET.RUND.RUNF.EXC.C."
    Dim c As Range
    With ThisWorkbook.Sheets(1)
        For Each c In .Range("AR1:AR" & .Range("AR" & .Rows.Count).End(xlUp).Row)
            If InStr(HIDE, "." & c & ".") Then
                c.EntireRow.Hidden = True
            End If
        Next
    End With
End Sub
Excel Hero
  • 14,253
  • 4
  • 33
  • 40
  • `In ThisWorkbook.Sheets(1).Range("A1:AR1")`? Why `A1:AR1`? and not `A1:AR & Lastrow`? – Siddharth Rout Sep 12 '15 at 16:58
  • Also if a cell has `DRIN.DRIR` then your code will give a false positive because of `"." & c & "."` :) – Siddharth Rout Sep 12 '15 at 17:00
  • Of course, but such values were not specified and in truth extremely unlikely. – Excel Hero Sep 12 '15 at 17:05
  • It is almost a certaintude that OP's AR column contains discreet values similar to his array elements. At any rate, he is free to use whatever delimiter (other than periods) in the constant to facilitate unique matches. – Excel Hero Sep 12 '15 at 17:31
  • You are almost assuredly correct in the assumption that Chr(46) could be used as a delimiter but I've been bitten in the backside enough times that I habitually use a *very* odd abstract character as a delimiter. My current favorite is ChrW(8203) which is a unicode zero-length space. That used to be common in Atom feeds but I have yet to have it present a false positive as a delimiter in the method you've described. –  Sep 12 '15 at 23:26
  • @Jeeped Yes. I've been coding routines like this in BASIC for two decades longer than Excel has existed. I simply change to whatever delimiter is appropriate for the given project. – Excel Hero Sep 13 '15 at 05:15
  • @ExcelHero - Just trying to keep the answer pertinent for the ~375 other programmers that will find this answer in their own quest for a solution. –  Sep 13 '15 at 05:21
  • correct coding which i am using :Sub newfilter() Cncl = Application.WorksheetFunction.CountA(ThisWorkbook.Sheets(1).Range("E:E")) cncl1 = Application.WorksheetFunction.CountA(ThisWorkbook.Sheets(2).Range("E:E")) ThisWorkbook.Sheets(1).Range("A1:AR" & Cncl).AutoFilter Field:=6, Criteria1:="*Cancellation*", Operator:=xlAnd ThisWorkbook.Sheets(1).Range("A1:AR" & Cncl).AutoFilter Field:=11, Criteria1:="COD", Operator:=xlAnd – Dharmendra Sep 13 '15 at 18:47
  • ThisWorkbook.Sheets(1).Range("A1:AR" & Cncl).AutoFilter Field:=16, Criteria1:="0.00", Operator:=xlAnd ThisWorkbook.Sheets(1).Range("A1:AR" & Cncl).AutoFilter Field:=18, Criteria1:="0.00", Operator:=xlAnd ThisWorkbook.Sheets(1).Range("A1:AR" & Cncl).AutoFilter Field:=23, Criteria1:="0.00", Operator:=xlAnd – Dharmendra Sep 13 '15 at 18:50
  • ThisWorkbook.Sheets(1).Range("A1:AR" & Cncl).AutoFilter Field:=27, Criteria1:=Array("<>C", "<>DRCA", "<>DRCA", "<>DREX", "<>DRFU", "<>DRIN", "<>DRIR", "<>DRND", "<>DRPN", "<>DRPR", "<>DRRE", "<>DRUN", "<>DRUN", "<>EXC", "<>EXCD", "<>REXC", "<>RFUR", "<>RINV", "<>RIRC", "<>RNDR", "<>RPNA", "<>RPRO", "<>RRET"), Operator:=xlFilterValues – Dharmendra Sep 13 '15 at 18:50
  • everything is working fine except last condition; hope you all will able to suggest be shortest coding for this. – Dharmendra Sep 13 '15 at 18:51
  • @Dharmendra Your last condition will never work. As I mentioned at the beginning of my answer, `You cannot use the AutoFilter from VBA to explicitly exclude more than two values for a given field.` This means that if you have more than TWO of theses `<>XXXX` it will not result in the correct filter. Instead you must tell the filter what you want... not what you do not want. Sid's answer takes this approach. He inverts the list into what you do want and gives that to the autofilter. My answer here takes a simpler approach. Instead of using the autofilter I just hide the rows you do not want. – Excel Hero Sep 13 '15 at 18:56
  • @Dharmendra – please accept most helpful answer by clicking on check mark right below voting buttons (See [tour] to see where the checkmark is.) – miroxlav Sep 22 '15 at 20:55