wake-up-neo.com

Allgemeine Methode zum Überprüfen, ob sich ein Schlüssel in einer Sammlung in Excel VBA befindet

Ich habe verschiedene Collections in meinem Code. Einige enthalten Objekte (verschiedener Art), andere haben Typen (wie Long).

Gibt es eine Möglichkeit, zu überprüfen, ob ein Schlüssel in der Collection enthalten ist, der für Typen sowie für Objekte geeignet ist?

Bisher habe ich zwei Funktionen.

Erste funktion:

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

Zweite Funktion:

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

Der Grund für die beiden Funktionen ist, dass ContainsObject nicht zu funktionieren scheint, wenn ich eine Collection mit Longs-Paaren übergeben (die Funktion gibt immer False zurück.)

P.S .: Die erste Funktion ist eine Kopie der dritten Antwort von Test oder Prüfung, ob ein Blatt vorhanden ist

8
user2606240

Sie sollten eine Variant in der ersten Funktion verwenden. Sie können eine Object einer Variant zuweisen, z. Das wird kein Fehler sein:

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

Dies gibt jedoch einen Type Mismatch-Kompilierungsfehler, d. H. Der Versuch, eine Long einer Object zuzuweisen:

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

Für eine generische Funktion (entlang der Zeilen Ihres Codes) zur Überprüfung, ob ein Collection-Schlüssel gültig ist, können Sie Folgendes verwenden:

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

Testcode:

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

Zu MSDN gibt es einen nützlichen Artikel dazu. Der Kontext ist VB6, bezieht sich jedoch auf VBA.

12
Robin Mackenzie

Einige Tippfehler wie in den Kommentaren wurden bereits während der Bearbeitung Ihres Beitrags korrigiert .. __ Als Antwort auf Ihre Frage möchte ich verwandte Aspekte behandeln.
Das Verwenden von Schlüsseln in Sammlungen hat hauptsächlich drei Vorteile.
- Wenn sich die Bestellung ändert, greift Ihr Code immer noch auf den korrekten Artikel zu - Sie können direkt auf das Objekt zugreifen, ohne die gesamte .__ zu lesen. Sammlung
- Es kann den Code lesbarer machen.

* Aber gleichzeitig gibt es hauptsächlich drei Probleme bei der Verwendung von Schlüsseln in Sammlungen

  • Sie können nicht prüfen, ob der Schlüssel vorhanden ist

  • Sie können den Schlüssel nicht ändern

  • Sie können den Schlüssel nicht abrufen

Gemäß dem Pearsons-Artikel sind die Schlüssel einer Collection nur schreibgeschützt. Es gibt keine Möglichkeit, eine Liste der vorhandenen Keys einer Collection abzurufen. Weiter gehender zitierter Absatz: -

Hier ist Coll ein Collection-Objekt, in dem mehrere .__ gespeichert werden. CFile-Objekte. Die CollKeys-Sammlung wird zum Speichern der Schlüssel von .__ verwendet. die in der Coll Collection gespeicherten CFile-Objekte. Wir brauchen diese Sekunde Collection, da die Schlüssel einer Collection schreibgeschützt sind - Es gibt keine Möglichkeit, eine Liste der vorhandenen Schlüssel einer Sammlung abzurufen. Einer der Verbesserungen, die von CFiles bereitgestellt werden, sind die Möglichkeit, eine Liste von .__ abzurufen. Schlüssel für die Sammlung.

Benutzerdefinierte Sammelklassen

Eine Möglichkeit besteht darin, die Mitglieder der Auflistung zu durchlaufen und zu prüfen, ob Übereinstimmungen für das gefunden werden, wonach Sie suchen. Die andere Möglichkeit besteht darin, den Item not in collection-Fehler abzufangen und dann ein Flag zu setzen, das besagt, dass das Element nicht vorhanden ist. Die Meinungen unterscheiden sich bei diesen Ansätzen, während einige Leute der Meinung sind, dass es keine gute Methode ist, um Fehler zu erkennen, während der andere Abschnitt der Ansicht ist, dass er für jede mittlere bis große Sammlung wesentlich schneller als die Iteration sein wird.
Wenn wir also eine Methode zum Abfangen von Fehlern suchen, dann hängt die Fehlernummer, die wir erhalten, davon ab, was genau den Fehler verursacht hat. Wir benötigen eine Code-Routine, um den Fehler zu überprüfen. Auf einfachste Weise könnte es sein.

'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

Die von verschiedenen Fachleuten vorgeschlagenen Routinen zum Erfassen von Fehlern unterscheiden sich in der Fehlernummer, die sie für wichtig halten und in ihre Routine aufnehmen. Verschiedene häufig auftretende Fehlernummern, die mit dem Auflistungsobjekt verknüpft sind, lauten: 

  • Error 5 Ungültiger Prozeduraufruf oder -argument. Dieser Fehler kann auch auftreten , wenn versucht wird, eine Prozedur aufzurufen, die auf der aktuellen Plattform nicht gültig ist. Beispielsweise sind einige Verfahren möglicherweise nur fürMicrosoft Windows oder für den Macintosh usw. gültig.
  • error 438 "object unterstützt diese Eigenschaft oder Methode nicht. Ein objectist eine Klasseninstanz. Eine Klasseninstanz unterstützt einige Eigenschaften , die in dieser Klassentypdefinition definiert sind, und unterstützt diese nicht.
  • Error 457 Dieser Schlüssel ist bereits einem Element von this zugeordnetcollection. Sie haben einen Schlüssel für ein Sammlungsmitglied angegeben, das bereits ein anderes Mitglied der Sammlung identifiziert. Wählen Sie einen anderen Schlüssel Für dieses Mitglied.
  • Error 91 Objektvariable oder With-Blockvariable nicht gesetzt. Zum Erstellen einer Objektvariablen gibt es zwei Schritte Zuerst müssen Sie die Objektvariable .__ deklarieren. Dann müssen Sie mit der Set-Anweisung einen gültigen Verweis auf die Variable des Objekts Zuweisen. Sie haben versucht, eine Objektvariable zu verwenden, die noch kein gültiges Objekt referenziert.
  • Error 450 Falsche Anzahl von Argumenten oder ungültige Eigenschaft Zuordnung. Die Anzahl der Argumente im Aufruf der Prozedur stimmte nicht mit der Anzahl der erforderlichen Argumente überein, die von der -Prozedur erwartet wurden. Wenn Sie versucht haben, sie zuzuweisen einen Wert für eine schreibgeschützte Eigenschaft,

Unter den obigen Fehlern wurde die Fehlernummer 438 als wichtig angesehen, und der andere ist 5. Ich füge eine Funktion-Routine in mein Beispieltestprogramm ein, die von Mark Nold vor 7 Jahren im Jahr 2008 veröffentlicht wurde. Vide SO question Determining ob ein Objekt Mitglied einer Sammlung in der VBA ist mit gebührender Anerkennung.

Einige Fehler wie der Fehler 457 sind zum Zeitpunkt des Programmtestlaufs nicht zulässig. Ich habe versucht, mit doppelten Schlüsseldaten aufzufüllen, es gab den Fehler zum Zeitpunkt des Programmtests, wie in der Momentaufnahme gezeigt  error 457

Nach dem Entfernen wird die korrekte Ausgabe angezeigt, wie im Schnappschuss gezeigt. 

 no error

Es ist möglicherweise nicht möglich, die Liste der Schlüssel einer Sammlung mit einer Vanilla-Sammlung abzurufen, ohne die Schlüsselwerte in einem unabhängigen Array zu speichern. Die einfachste Alternative, dies zu tun, besteht darin, einen Verweis auf die Microsoft Scripting Runtime hinzuzufügen und stattdessen ein leistungsfähigeres Wörterbuch zu verwenden .. Diese Methode wurde hinzugefügt, um die Liste der Schlüssel in meinem Programm zu erhalten.
Beim Auffüllen von Collection muss sichergestellt werden, dass der Schlüssel der zweite Parameter ist und eine eindeutige Zeichenfolge sein muss.

Vollständiger Code meines Programms ist.

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

Die endgültige Ausgabe gemäß Programm, wie im Direktfenster gezeigt, wurde im Snapshot angezeigt.
 enter image description here

4
skkakkar

Die Methode von Robin schlägt fehl, wenn die Collection Objekte statt primitiver Typen enthält, da diese mit Set zugewiesen werden müssen und ansonsten ein Fehler generiert wird, der dazu führt, dass die Methode False zurückgibt. Hier ist eine kleine Anpassung:

'Test if a key is available in a collection
Public Function HasKey(coll As Collection, strKey As String) As Boolean
    On Error GoTo IsMissingError
        Dim val As Variant
'        val = coll(strKey)
        HasKey = IsObject(coll(strKey))
        HasKey = True
        On Error GoTo 0
        Exit Function
IsMissingError:
        HasKey = False
        On Error GoTo 0
End Function
0
Apostle

Apostel ist mit ihrer Antwort fast richtig. Robins Antwort funktioniert nicht mit generischen Objekten, sondern funktioniert wie geschrieben, da das Range-Objekt von Excel den Wert der Zelle zurückgibt. Ich liebe die Verwendung von IsObject durch Apostel (vor allem, weil ich genau das herausgefunden hatte). Der Code ist jedoch etwas zu kompliziert.

Wenn der Schlüssel in der Auflistung vorhanden ist, setzt IsObject die Variante auf True oder False. Andernfalls wird ein Fehler ignoriert, wenn die Variante leer bleibt.

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
0
PaulE