如何快速判断数组中是否包含某个值

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/taller_2000/article/details/80058667

多维数组是经常用到的数据结构,判断数组中是否包含某个元素的常规办法就是变量整个数组,逐个对比。自定义函数如下:

Function ItemInArrayLoop(aData, vEle) As Boolean
    ItemInArrayLoop = False
    For i = 1 To ubund(aData, 1)
        For j = 1 To UBound(aData, 2)
            If aData(i, j) = vItem Then
                ItemInArrayLoop = True
                Exit Function
            End If
        Next j
    Next i
End Function

函数返回值为布尔类型。简单的测试代码:

Sub DEMO_LOOP()
    Dim a(1 To 10, 1 To 10), b(1 To 10, 1 To 10), i, j
    For i = 1 To 10
        For j = 1 To 10
            a(i, j) = i + j
            b(i, j) = CStr(i + j)
        Next
    Next
    Debug.Print ItemInArrayLoop(a(), 10) ' True
    Debug.Print ItemInArrayLoop(a(), 20) ' False, 没有20
    Debug.Print ItemInArrayLoop(a(), "10")   ' False, 数据类型不匹配
    Debug.Print ItemInArrayLoop(b(), "10")   ' True
End Sub

在数组元素比较多或者维度维度比较多的时候,循环判断效率就会较低。既然是VBA的解决方案,肯定可以考虑利用工作表还是来提高效率。
工作表函数MATCH进行快速判断数组中是否包含某个值,但是只支持一维数组,幸运的是,
工作表函数INDEX可以用来实现数组切片,也就是多维数组的一部分可以转换为一维数组。

Function ItemInArray(aData, vEle) As Boolean
    ItemInArray = False
    If VBA.IsArray(aData) Then
        For i = LBound(aData, 2) To UBound(aData, 2)
            ItemInArray = Not (IsError(Application.Match(vEle, Application.Index(aData, , i), 0)))
            If ItemInArray Then Exit Function
        Next i
    End If
End Function

测试代码如下,结果与循环判断完全相同。

Sub DEMO()
    Dim a(1 To 10, 1 To 10), b(1 To 10, 1 To 10), i, j
    For i = 1 To 10
        For j = 1 To 10
            a(i, j) = i + j
            b(i, j) = CStr(i + j)
        Next
    Next
    Debug.Print ItemInArray(a(), 10) ' True
    Debug.Print ItemInArray(a(), 20) ' False, 没有20
    Debug.Print ItemInArray(a(), "10")   ' False, 数据类型不匹配
    Debug.Print ItemInArray(b(), "10")   ' True
End Sub

VBA的Fitler函数可以实现在数组中查找,但是有如下限制:

  • 必须是String数组
  • 不能实现精确查找
    例如下面代码中数组a()包含1到10,使用Filter查找”1”,返回的结果是两个元素,数组元素’10’也在结果数组中,因此ItemInArray中的MATCH不能简单的用Filter代替。
Sub DEMO_FILTER()
    Dim a(1 To 10) As String, i, aRes
    For i = 1 To 10
        a(i) = i
    Next
    aRes = VBA.Filter(a(), "1")
    Debug.Print Join(aRes, ",")
End Sub

对于字符串数组,如果数组元素是规范的数据,那么使用INSTR判断会更加简洁。

Sub DEMO()
    aKey = Array("R01", "R02", "R03")
    ' option 1
    sKeyList = Join(aKey, "|")
    Debug.Print InStr(1, sKeyList, "R01", vbTextCompare) > 0
    Debug.Print InStr(1, sKeyList, "R11", vbTextCompare) > 0
    ' option 2
    Debug.Print UBound(VBA.Filter(aKey, "R01", , vbTextCompare)) = 0
    Debug.Print UBound(VBA.Filter(aKey, "R11", , vbTextCompare)) = 0 ' 不存在时,Ubound返回的结果为-1
End Sub

先用JOIN函数将数组连接为一个字符串,数据元素用”|”作为分隔符,然后使用INSTR判断查找的字符是否包含在该字符串中。这个应用场景中,也可以使用FILTER函数实现。

猜你喜欢

转载自blog.csdn.net/taller_2000/article/details/80058667