使用 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@ 等于 abIsInArray( "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 slower Match) 支持StringIntegerBoolean (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 检查值是不是在数组中的主要内容,如果未能解决你的问题,请参考以下文章

excel vba 数组中第1位字符为0,赋给单元格时如何将0保留?

Excel函数从没有VBA的值构造数组

Excel VBA - 确定数组 UDF 的列或行目标

excel VBA - 从函数中重新获得可变长度数组

识别不同的动态数组 VBA Excel

Excel VBA检查各种组合框中是不是存在值,然后添加相应的文本框值