使用 Excel VBA 检查值是不是在数组中
Posted
技术标签:
【中文标题】使用 Excel VBA 检查值是不是在数组中【英文标题】:Check if a value is in an array or not with Excel VBA使用 Excel VBA 检查值是否在数组中 【发布时间】:2016-07-08 13:29:16 【问题描述】:我在下面有一些代码,应该是检查一个值是否在一个数组中。
Sub test()
vars1 = Array("Examples")
vars2 = Array("Example")
If IsInArray(Range("A1").Value, vars1) Then
x = 1
End If
If IsInArray(Range("A1").Value, vars2) Then
x = 1
End If
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
如果单元格A1
包含单词Examples
,由于某种原因,两个IsInArray
都检测到它对于两个数组都存在,而它应该只发现它存在于vars1
数组中
我需要进行哪些更改才能使我的 IsInArray
函数完全匹配?
【问题讨论】:
你的意思是当单元格A1包含“示例”时,函数IsInArray检测到它们? 【参考方案1】:你可以像这样暴力破解它:
Public Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
Dim i
For i = LBound(arr) To UBound(arr)
If arr(i) = stringToBeFound Then
IsInArray = True
Exit Function
End If
Next i
IsInArray = False
End Function
使用喜欢
IsInArray("example", Array("example", "someother text", "more things", "and another"))
【讨论】:
在我的原始代码中更改IsInArray
函数以改用 IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
是否有任何好处/坏处?
您的阵列有多大?这比其他方法更具可读性吗?这可能只是偏好,因为迭代数组非常快,而且(虽然我不能肯定地说)Match 函数肯定基本上是这样做的。
我正在通过IsInArray
运行 10~ 个数组,目前所有这些数组加起来总共有 501 个数组项。它最终会变得更大/更多。
这些数字很小。我不确定无论哪种方式你都会看到很大的不同。第三个选项是Dictionary
对象。它有一个Exists
方法并且比数组更容易使用(添加项目时没有ReDim Preserve
)
@Ryflex @Slai 可能有点晚了,但我想澄清一下,使用 Match()
函数实际上比仅遍历(循环)数组要慢得多。我对一个大小为 2000 的数组进行了测试。循环遍历数组的最坏情况是寻找最后一项(在索引 2000 处)。在对 Match()
函数和循环进行 5000 次调用后,Match()
的总时间为 3.746094
,但只有 1.667969
用于循环遍历数组。 Check the answer to this question for the code I used in my testing【参考方案2】:
这个问题在这里被问到:VBA Arrays - Check strict (not approximative) match
Sub test()
vars1 = Array("Examples")
vars2 = Array("Example")
If IsInArray(Range("A1").value, vars1) Then
x = 1
End If
If IsInArray(Range("A1").value, vars2) Then
x = 1
End If
End Sub
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
End Function
【讨论】:
在excel中不需要循环遍历数组,因为excel有强大的match()函数来做比较。 @Sixthsense 这不会循环遍历数组 在此处查看关于Match
而不是 looping 的性能问题的评论:***.com/questions/38267950/…【参考方案3】:
我搜索了这个问题,当我看到答案时,我最终创建了一些不同的东西(因为大多数时候我喜欢更少的代码而不是大多数其他东西),这些东西在绝大多数情况下都应该有效。基本上是把数组变成一个字符串,数组元素用某个分隔符分隔,然后将搜索值包裹在分隔符中,通过instr。
Function is_in_array(value As String, test_array) As Boolean
If Not (IsArray(test_array)) Then Exit Function
If InStr(1, "'" & Join(test_array, "'") & "'", "'" & value & "'") > 0 _
Then is_in_array = True
End Function
你会像这样执行函数:
test = is_in_array(1, array(1, 2, 3))
【讨论】:
【参考方案4】:使用 Excel VBA 中的 Match() 函数来检查值是否存在于数组中。
Sub test()
Dim x As Long
vars1 = Array("Abc", "Xyz", "Examples")
vars2 = Array("Def", "IJK", "MNO")
If IsNumeric(Application.Match(Range("A1").Value, vars1, 0)) Then
x = 1
ElseIf IsNumeric(Application.Match(Range("A1").Value, vars2, 0)) Then
x = 1
End If
MsgBox x
End Sub
【讨论】:
我将IsInArray
函数改为使用IsInArray = Not IsError(Application.Match(stringToBeFound, arr, 0))
解决了问题
Not IsError() 和 IsNumeric() 与 Match() 函数一起使用时,结果相同:)【参考方案5】:
如果没有匹配,以下函数将返回“0”,如果匹配则返回“正整数”:
Function IsInArray(stringToBeFound As String, arr As Variant) As Integer
IsInArray = InStr(Join(arr, ""), stringToBeFound)
End Function
_______________________________________________________________________________
注意:该函数首先使用 'Join' 将整个数组内容连接到一个字符串(不确定连接方法是否在内部使用循环),然后使用InStr.
【讨论】:
只有在arr
项目和 stringToBeFound
不包含 ,
字符/分隔符时才有效!
我也用','试过了,但它仍然有效!在 botb the arr 和 stringToBeFound 中用 'Exampl,es' 替换了 'Examples'。我错过了什么吗?顺便说一句,我的代码中有一个错字:现在将 IsInArray = InStr(Join(arr, "), stringToBeFound) 更改为 IsInArray = InStr(Join(arr, ""), stringToBeFound)
我的意思是“只会工作......可靠”......IsInArray( "ab", ("ab,c","d"))
将返回True
,但它应该返回False
,因为两个数组项都不是ab,c
也不是@ 987654329@ 等于 ab
。 IsInArray( "ab,c", ("ab","c"))
也一样【参考方案6】:
虽然这基本上只是@Brad 的回答,但我认为可能值得包含一个稍微修改的函数,如果它存在于数组中,它将返回您正在搜索的项目的索引。如果该项目不在数组中,则返回-1
。
这个的输出可以像“in string”函数一样检查,If InStr(...) > 0 Then
,所以我在它下面做了一个小测试函数作为例子。
Option Explicit
Public Function IsInArrayIndex(stringToFind As String, arr As Variant) As Long
IsInArrayIndex = -1
Dim i As Long
For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i) = stringToFind Then
IsInArrayIndex = i
Exit Function
End If
Next i
End Function
Sub test()
Dim fruitArray As Variant
fruitArray = Array("orange", "apple", "banana", "berry")
Dim result As Long
result = IsInArrayIndex("apple", fruitArray)
If result >= 0 Then
Debug.Print chr(34) & fruitArray(result) & chr(34) & " exists in array at index " & result
Else
Debug.Print "does not exist in array"
End If
End Sub
然后我有点过分了,为二维数组充实了一个,因为当你 generate an array based on a range 它通常是这种形式。
它返回一个只有两个值的单维变量数组,数组的两个索引用作输入(假设找到了值)。如果未找到该值,则返回(-1, -1)
的数组。
Option Explicit
Public Function IsInArray2DIndex(stringToFind As String, arr As Variant) As Variant
IsInArray2DIndex= Array(-1, -1)
Dim i As Long
Dim j As Long
For i = LBound(arr, 1) To UBound(arr, 1)
For j = LBound(arr, 2) To UBound(arr, 2)
If arr(i, j) = stringToFind Then
IsInArray2DIndex= Array(i, j)
Exit Function
End If
Next j
Next i
End Function
这是我为测试设置的数据图片,然后是测试:
Sub test2()
Dim fruitArray2D As Variant
fruitArray2D = sheets("Sheet1").Range("A1:B2").value
Dim result As Variant
result = IsInArray2DIndex("apple", fruitArray2D)
If result(0) >= 0 And result(1) >= 0 Then
Debug.Print chr(34) & fruitArray2D(result(0), result(1)) & chr(34) & " exists in array at row: " & result(0) & ", col: " & result(1)
Else
Debug.Print "does not exist in array"
End If
End Sub
【讨论】:
【参考方案7】:我想提供另一个应该性能强大的变体,因为
它不使用sometimes slowerMatch
)
支持String
、Integer
、Boolean
等 (not String
-only)
返回搜索项的索引
支持第n次出现
...
'-1 if not found
'https://***.com/a/56327647/1915920
Public Function IsInArray( _
item As Variant, _
arr As Variant, _
Optional nthOccurrence As Long = 1 _
) As Long
IsInArray = -1
Dim i As Long: For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i) = item Then
If nthOccurrence > 1 Then
nthOccurrence = nthOccurrence - 1
GoTo continue
End If
IsInArray = i
Exit Function
End If
continue:
Next i
End Function
像这样使用它:
Sub testInt()
Debug.Print IsInArray(2, Array(1, 2, 3)) '=> 1
End Sub
Sub testString1()
Debug.Print IsInArray("b", Array("a", "b", "c", "a")) '=> 1
End Sub
Sub testString2()
Debug.Print IsInArray("b", Array("a", "b", "c", "b"), 2) '=> 3
End Sub
Sub testBool1()
Debug.Print IsInArray(False, Array(True, False, True)) '=> 1
End Sub
Sub testBool2()
Debug.Print IsInArray(True, Array(True, False, True), 2) '=> 2
End Sub
【讨论】:
【参考方案8】:你想检查 Example 是否存在于 Range("A1").Value 中,如果失败,那么检查 Example 对吗?我认为 mycode 会完美运行。请检查。
Sub test()
Dim string1 As String, string2 As String
string1 = "Examples"
string2 = "Example"
If InStr(1, Range("A1").Value, string1) > 0 Then
x = 1
ElseIf InStr(1, Range("A1").Value, string2) > 0 Then
x = 2
End If
结束子
【讨论】:
是的,Examples
存在于 A1 中,我不能像您使用的那样使用字符串,我的代码有一个数组,否则我通常会使用 InStr
以上是关于使用 Excel VBA 检查值是不是在数组中的主要内容,如果未能解决你的问题,请参考以下文章