版权声明:本文为博主原创文章,转载请注明出处。 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
函数实现。