excel 使用字典自动筛选多个条件

cbjzeqam  于 2023-05-08  发布在  其他
关注(0)|答案(3)|浏览(226)

我尝试使用数组筛选具有多个条件的列。
我认为可以使用字典来完成,就像这个问题的公认答案Link一样。
我适应了代码一点,但我得到(类型不匹配错误)在这一行:
If Application.Match(filter_Criteria(i), subStrings, 0) Then

:如果有其他答案(不使用帮助栏),非常欢迎。

Sub AutoFilter_With_Multiple_Criteria()

    Const filter_Column As Long = 2
    Const filter_Delimiter As String = " "
    
    Dim filter_Criteria() As Variant
    filter_Criteria = Array("Cathodic Protection", "C.P", "Riser")
    
    Dim ws As Worksheet:    Set ws = ActiveSheet
    
    Dim rg As Range
    Set rg = ws.UsedRange.Resize(ws.UsedRange.Rows.count - 1).Offset(1) 'the source range (UsedRange except the first Row)

    Dim rCount As Long, arr() As Variant
    rCount = rg.Rows.count - 1
    arr = rg.Columns(filter_Column).Resize(rCount).Offset(1).value      'Write the values from criteria column to an array.
        
    Dim dict As New Dictionary                                    'Write the matching strings to the keys (a 1D array) of a dictionary.
    
    Dim subStrings() As String, r As Long, i As Long, rStr As String
    
    For r = 1 To rCount                                           'Loop through the elements of the array.
        rStr = arr(r, 1)                                          'Convert the current value to a string and store it in a variable.
        If Len(rStr) > 0 Then                                     'is not blank
           subStrings = Split(rStr, filter_Delimiter)                 'Split the string into an array.
            For i = 0 To UBound(filter_Criteria)
              If Application.Match(filter_Criteria(i), subStrings, 0) Then
                If Not dict.Exists(rStr) Then
                    dict(rStr) = Empty
                End If
              End If
            Next i
        End If
    Next r
    
    If dict.count > 0 Then
        rg.AutoFilter Field:=filter_Column, Criteria1:=dict.Keys, Operator:=xlFilterValues   'use the keys of the dictionary (a 1D array) as a Criteria
    End If
    
End Sub
sycxhyv7

sycxhyv71#

如果您需要按单元格包含任何criteria数组元素进行过滤,请尝试下一个改编代码。它假设你需要在第一列(A:A)上进行过滤:

Sub AutoFilter_With_Multiple_Criteria()

    Const filter_Column As Long = 1 'column A:A
    
    Dim filter_Criteria() As Variant: filter_Criteria = Array("*Cathodic Protection*", "*C.P*", "*Riser*") 'changed array to avoid exact matches!
    
    Dim ws As Worksheet:    Set ws = ActiveSheet
    
    If ws.AutoFilterMode Then ws.AutoFilterMode = False
    
    Dim rg As Range
    Set rg = ws.UsedRange.Resize(ws.UsedRange.rows.count - 1).Offset(1) 'the source range (UsedRange except the first Row)

    Dim rCount As Long, arr() As Variant, El
    rCount = rg.rows.count - 1
    arr = rg.Columns(filter_Column).Resize(rCount).Offset(1).Value     'Write the values from criteria column to an array.
        
    Dim dict As New scripting.Dictionary                               'Write the matching strings to the keys (a 1D array) of a dictionary.
    
    Dim r As Long
    
    For r = 1 To rCount                                               'Loop through the elements of the array.
        If Len(arr(r, 1)) > 0 Then                                    'is not blank
            For Each El In filter_Criteria
                If arr(r, 1) Like El Then dict(arr(r, 1)) = vbNullString: Exit For
            Next El
        End If
    Next r
    
    If dict.count > 0 Then
        rg.AutoFilter field:=filter_Column, Criteria1:=dict.keys, Operator:=xlFilterValues   'use the keys of the dictionary (a 1D array) as a Criteria
    End If
    
End Sub

编辑

如果你需要相反的方法(过滤不匹配任何数组元素的内容),你应该用下面的方式改变字典加载迭代:

Dim boolFound as Boolean

    For r = 1 To rCount                                           
        If Len(arr(r, 1)) > 0 Then                               
            boolFound = False
            For Each El In filter_Criteria
                If arr(r, 1) Like El Then boolFound = True: Exit For
           Next El
           If Not boolFound Then dict(CStr(arr(r, 1))) = vbNullString 'CStr used in case of numeric values, which be converted to string in order to be taken in consideration...
        End If
    Next r
    Debug.Print Join(dict.keys, "|"): Stop 'just to see the new built array...
f5emj3cl

f5emj3cl2#

字典自动过滤

阵列(挑剔!?)

  • 为了确保Array函数返回一个从零开始的数组,你最好使用下面的(VBA.):
filter_Criteria = VBA.Array("Cathodic Protection", "C.P", "Riser")
  • 如果你不想执行前面的操作,可以使用下面的代码(LBound(几个顶级贡献者推荐)):
For i = LBound(filter_Criteria) To UBound(filter_Criteria)
  • 使用Split函数时,生成的数组始终是一个从零开始的一维字符串数组。
    循环
  • 循环会降低代码的速度。只要“可能”(合理),你就应该避免它们。到时候你会知道什么时候是合理的。
  • 在这种情况下,很难理解如何做到这一点(请参阅续篇中的When using an array...)。
    申请.匹配
  • 当使用简单数据类型作为Application.Match中的第一个参数时,结果将始终是数字或错误值(错误2042)。使用以下内容测试结果:
If IsNumeric(Application.Match(filter_Criteria(i), subStrings, 0)) Then

这与第一次发布的对这个问题的回答类似。

  • 当使用数组或范围作为Application.Match中的第一个参数时,结果将始终是数字和/或错误值的基于一的数组(1D或2D)。你可以使用Application.Count来计数(或检查)匹配,从而避免循环,也不用关心数组的初始部分:
With Application
    If .Count(.Match(filter_Criteria, subStrings, 0)) > 0 Then
        If Not...
            '''
        End If
    End If 
End With
koaltpgm

koaltpgm3#

问题是此行中的类型不匹配,这是由“Application.Match”没有返回bool值引起的。

If Application.Match(filter_Criteria(i), subStrings, 0) Then

所以你需要像这样重写:

If Not IsError(Application.Match(filter_Criteria(i), subStrings, 0)) Then

相关问题