在Excel VBA中,检查一个键是否在集合中的通用方法。

11 浏览
0 Comments

在Excel VBA中,检查一个键是否在集合中的通用方法。

我的代码中有不同的集合。一些保存对象(各种各样的对象),而其他集合中包含类型(例如Long)。\n有没有办法检查集合中是否包含某个键,既适用于类型也适用于对象?\n到目前为止,我有两个函数。\n第一个函数:\n

Private Function ContainsObject(objCollection As Object, strName As String) As Boolean
    Dim o As Object
    On Error Resume Next
    Set o = objCollection(strName)
    ContainsObject = (Err.Number = 0)
    Err.Clear
End Function

\n第二个函数:\n

Private Function ContainsLong(AllItems As Collection, TheKey As String) As Boolean
    Dim TheValue As Long
    On Error Resume Next
    TheValue = AllItems.Item(TheKey)
    ContainsLong = (Err.Number = 0)
    Err.Clear
End Function

\n之所以有两个函数,是因为如果我传递一个包含Long键值对的集合给ContainsObject函数,它似乎不起作用(该函数总是返回False)。\n附注:第一个函数是从Test or check if sheet exists的第三个答案中复制的。

0
0 Comments

问题的出现原因是在Excel VBA中,需要一种通用的方法来检查一个键是否存在于一个集合中。而解决方法是使用IsObject函数和错误处理来检查键是否存在于集合中。

以下是整理后的文章:

在Excel VBA中,我们经常需要检查一个键是否存在于一个集合中。然而,Excel VBA并没有提供一个直接的方法来实现这个功能。因此,我们需要自己编写一个通用的方法来解决这个问题。

首先,让我们来看一下一个错误的解决方法。Robin提供的答案是错误的,因为它不适用于通用对象。但是,它在Excel的Range对象中可以正常工作,因为Range对象会返回单元格的值。

接下来,让我们来看一下一个正确的解决方法。Apostle提供了一个使用IsObject函数的方法来检查键是否存在于集合中,并且我也认同这个方法。然而,这段代码有点过于复杂。

下面是一个简化的版本的代码:

Function HasKey(col As Collection, Key As String) As Boolean
    Dim v As Variant
    On Error Resume Next
    v = IsObject(col.Item(Key))
    HasKey = Not IsEmpty(v)
End Function

这段代码的原理是,如果键存在于集合中,IsObject函数会将变量v设置为True或False,否则将会发生错误,并且错误会被忽略,导致变量v为空。

最后,通过检查变量v是否为空,我们可以确定键是否存在于集合中。如果变量v不为空,则说明键存在于集合中,函数返回True;否则,返回False。

使用这个通用的方法,我们可以方便地检查一个键是否存在于一个集合中,从而更好地控制我们的Excel VBA代码。

0
0 Comments

在Excel VBA中,检查一个键是否在集合中有通用的方法。使用键在集合中有以下三个主要优点:

- 如果顺序发生变化,你的代码仍然可以访问正确的项

- 您可以直接访问该项,而无需阅读整个集合

- 它可以使您的代码更易读

但是,使用键在集合中也有三个主要问题:

- 无法检查键是否存在

- 无法更改键

- 无法检索键

根据Pearson的文章,集合的键是只写的,没有办法获取集合的现有键的列表。可以使用第二个集合来存储存储在Coll Collection中的CFile对象的键。我们需要这个第二个集合,因为集合的键是只写的,没有办法获取集合的现有键的列表。CFiles提供的其中一个改进是能够检索集合的键列表。

解决方法之一是遍历集合的成员,查看是否存在您要查找的内容,另一种方法是捕获"Item not in collection"错误,然后设置一个标志来表示该项不存在。对于这些方法,人们的意见不一。有些人认为捕获错误不是一种好的方法,而其他人则认为与迭代相比,对于任何中等到大型集合,捕获错误的方法会更快。

因此,如果我们选择捕获错误的方法,那么我们得到的错误号取决于错误的具体原因。我们需要一个检查错误的代码例程。最简单的方法是:

'c1 is the collection
For i = 1 To c1.Count
    Debug.Print Err.Number, Err.Description
    If Err.Number <> 0 Then Err.Clear
Next i

各种专业人士提出的捕获错误例程在考虑重要的错误号时有所不同。与集合对象相关的各种常见错误号包括:

- 错误5:无效的过程调用或参数。如果尝试调用当前平台上无效的过程,也可能发生此错误。例如,某些过程可能仅对Microsoft Windows或Macintosh等平台有效。

- 错误438:"对象不支持此属性或方法"。对象是类实例。类实例支持类类型定义中定义的一些属性,并且不支持这个属性。

- 错误457:该键已与此集合的一个元素关联。您为已经标识集合的另一个成员的集合成员指定了一个键。为该成员选择一个不同的键。

- 错误91:对象变量或With块变量未设置。创建对象变量有两个步骤。首先,您必须声明对象变量。然后,您必须使用Set语句为对象变量分配一个有效的引用。您尝试使用尚未引用有效对象的对象变量。

- 错误450:参数数量错误或无效的属性赋值。调用过程中的参数数量与过程所需的参数数量不同。如果尝试将值分配给只读属性,则会出现此错误。

在上述错误中,错误号438被认为很重要,另一个是5。我在我的示例测试程序中使用了Mark Nold在2008年发布的一种函数例程,该例程在SO问题"Determining whether an object is a member of a collection in VBA"中提到,并对他表示感谢。

某些错误,如错误457,在程序测试运行时将不被允许。我尝试使用重复的键数据来填充,它在程序测试时就会出错,如快照所示。

删除之后,它显示正确的输出,如快照所示。

对于一个普通的集合来说,可能无法获取集合的键列表,除非在独立数组中存储键值。最简单的替代方法是添加对Microsoft Scripting Runtime的引用,并使用一个更强大的字典。

我在我的程序中包含了这种获取键列表的方法。

在填充集合时,必须确保键是第二个参数,并且必须是唯一的字符串。

完整的程序代码如下:

Sub Generic_key_check()
    Dim arr As Variant
    Dim c1 As New Collection
    Dim dic As Object
    With Application
    .ScreenUpdating = False
    End With
    Set dic = CreateObject("Scripting.Dictionary")
    dic.CompareMode = vbTextCompare
    'Populate the collection
    c1.Add "sheet1", "sheet1"
    c1.Add "sheet2", "sheet2"
    c1.Add "sheet3", "sheet3"
    c1.Add "sheet4", "sheet4"
    c1.Add "sheet5", "sheet5"
    c1.Add 2014001, "Long1"
    c1.Add 2015001, "Long2"
    c1.Add 2016001, "Long3"
    c1.Add 2015002, "Long4"
    c1.Add 2016002, "Long5"
    'Populate the dictionary
    dic.Add "sheet1", "sheet1"
    dic.Add "sheet2", "sheet2"
    dic.Add "sheet3", "sheet3"
    dic.Add "sheet4", "sheet4"
    dic.Add "sheet5", "sheet5"
    dic.Add "Long1", 2014001
    dic.Add "Long2", 2015001
    dic.Add "Long3", 2016001
    dic.Add "Long4", 2015002
    dic.Add "Long5", 2016002
    ' Get a list of key items by Dictionary Method
    Dim N As Variant
    For Each N In dic.Keys
    Debug.Print "Key: " & N, "Value: " & dic.item(N)
    Next
    'Test for two types of data whether key exists or not.
    If InCollection(c1, "Long1") Then
    'If Exists("Long1", c1) Then
    Debug.Print "Good"
    Else
    ' If there is error then print out the error number and its description.
    Debug.Print Err.Number, Err.Description
    Debug.Print "Not Good"
    End If
    If InCollection(c1, "sheet2") Then
    Debug.Print "Good"
    Else
    Debug.Print Err.Number, Err.Description
    Debug.Print "Not Good"
    End If
    'Checking whether desired key has populated correctly
    Debug.Print c1("Sheet1")
    Debug.Print c1("Long3")
    'Listing out collection items to check theyexist in the collection.
    For i = 1 To c1.Count
    Debug.Print c1.item(i)
    Next i
    With Application
    .ScreenUpdating = True
    End With
    Set c1 = Nothing
End Sub
Public Function InCollection(col As Collection, key As String) As Boolean
    Dim var As Variant
    Dim errNumber As Long
    InCollection = False
    Set var = Nothing
    Err.Clear
    On Error Resume Next
    var = col.item(key)
    errNumber = CLng(Err.Number)
    On Error GoTo 0
    '5 is not in, 0 and 438 represent incollection
    If errNumber = 5 Then ' it is 5 if not in collection
    InCollection = False
    Else
    InCollection = True
    End If
End Function

程序的最终输出如下所示:

Key: sheet1, Value: sheet1
Key: sheet2, Value: sheet2
Key: sheet3, Value: sheet3
Key: sheet4, Value: sheet4
Key: sheet5, Value: sheet5
Key: Long1, Value: 2014001
Key: Long2, Value: 2015001
Key: Long3, Value: 2016001
Key: Long4, Value: 2015002
Key: Long5, Value: 2016002
Good
Good
Sheet1
2016001
sheet1
sheet2
sheet3
sheet4
sheet5
2014001
2015001
2016001
2015002
2016002

对于显示了Scripting Runtime库中Dictionary的应用程序,给予+1。真遗憾这不是Excel VBA的默认部分。

0
0 Comments

在Excel VBA中,检查集合中是否存在一个键的通用方法是使用Variant类型。可以将一个对象分配给Variant类型,例如,下面的代码不会出错:

Sub Test()
    Dim var As Variant
    Dim obj As Object
    Set obj = Application
    var = Application
    Debug.Print var
End Sub

但是,下面的代码会出现“类型不匹配”(Type Mismatch)的编译错误,即试图将Long类型赋值给一个Object类型:

Sub Test()
    Dim obj As Object
    Dim lng As Long
    lng = 3
    Set obj = lng
End Sub

因此,为了实现一个通用的函数来检查Collection中的键是否有效,可以使用以下代码:

Function HasKey(coll As Collection, strKey As String) As Boolean
    Dim var As Variant
    On Error Resume Next
    var = coll(strKey)
    HasKey = (Err.Number = 0)
    Err.Clear
End Function

测试代码如下:

Sub Test()
    Dim coll1 As New Collection
    coll1.Add Item:=Sheet1.Range("A1"), Key:="1"
    coll1.Add Item:=Sheet1.Range("A2"), Key:="2"
    Debug.Print HasKey(coll1, "1")
    Dim coll2 As New Collection
    coll2.Add Item:=1, Key:="1"
    coll2.Add Item:=2, Key:="2"
    Debug.Print HasKey(coll2, "1")
End Sub

MSDN上有一篇有关此问题的有用文章。虽然上下文是VB6,但与VBA相关联。

对于您明确且直截了当的答案,我已经点赞了。

- 感谢您的答案建议使用Dictionary对象,我同意这是首选的方法。OP正在使用Collection对象,可能没有机会切换到Dictionary。正如他们所说,不总是可以“中途换马”。

0