Fr. Sep 30th, 2022

Ich möchte euch hier ein paar Anwendungsmöglichkeiten des Scripting.Dictionary vorstellen, die einem das Leben in VBA sehr erleichtern. Meistens sind es Problemstellungen, die Zeit und somit Performance sparen sollen.
Dictionary ist kein Bestandteil der VBA Library, sie liegt in der Datei scrrun.DLL, deswegen muss sie eingebunden werden.

Early Binding versus Late Binding

Es gibt zwei Arten ein Dictionary in VBA einzubinden. Das ‘Early’ und das ‘Late’ Binding.
Beim ‘early binding‘ wird eine Referenz zur Microsoft Scripting Runtime im VBE-Projekt im Menüpunkt “Extras=>Verweise hergestellt.

VBE Extras Verweise
VBE Extras Verweise
VBE Extras Verweise MS Scripting Runtime
VBE Extras Verweise MS Scripting Runtime

Der Vorteil des ‘early binding’ liegt alleine in der zur Verfügung stehenden ‘Intellisense’ (den nach Eingabe eines Punktes hinter dem Object erscheinenden Methoden und Eigenschaften). Early Binding bezieht sich auf das Zurverfügungstellen dieser Methoden und Eigenschaften VOR der Laufzeit eures Programmes.

Beim ‘late binding’ wird das Object erst während der Laufzeit eures Programmes erzeugt und somit stehen einem dann diese Methoden und Eigenschaften nicht mehr in der Intellisense zur Verfügung.

Vorteile und Nachteile liegen hier beim Ersteller der Programme. Gute Programmierer nutzen die Intellisense während der Erstellung eines Programmes. Wenn sie das Programm dann ausliefern, stellen sie um auf ‘late binding’, um die Datei schlanker zu halten und auch um Kompatibilitätsprobleme beim Benutzer zu vermeiden.

Es ist auch nicht ratsam, ‘early binding’ einzustellen, wenn man das Objekt nur an ein oder zwei Stellen im Programm nutzt. Beim Early binding werden das Object und alle Methoden und Eigenschaften in der Exceldatei gespeichert.

Deklaration beider ‘Bindings’

'Early binding
Dim dict as New Dictionary
Set dict as New Dictionary

'Late binding
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")

Was kann ein Dictionary?

  • Ein Dictionary kann jede Art von Daten aufnehmen und ist anschliessend sehr schnell und einfach auszulesen.
  • Ein Dictionary  arbeitet im Arbeitsspeicher und ist somit sehr schnell. Wer bis jetzt Zelle für Zelle in Excel durchgearbeitet hat, wird mit Hilfe eines Dictionary einen sehr großen Geschwindigkeitsvorteil erreichen.
  • Ein Dictionary kann Daten speichern oder gruppieren, die einen eindeutigen Schlüssel (Key) haben.
  • Ein Dictionary kann Daten zu jederzeit aufnehmen.
  • Ein Dictionary kann nur eindeutige Schlüssel (Keys) aufnehmen und eignet sich daher sehr gut zur Erstellung von eindeutigen Listen in z.B. Excel. Wie das geht, erkläre ich weiter unten.
  • Ein Dictionary hat keine Sortierfunktion, daher sollte eine Sortierung schon vorher erfolgen.
  • Ein Dictionary nimmt Daten in der Reihenfolge auf, in der sie hinzugefügt werden.

Wie wird ein Dictionary ‘gefüllt’?

Ein Dictionary besteht aus einem eindeutigen Key und einem sogenannten ‘Item’, das mit einem Wert (value) belegt wird. Ich nenne in Klammern die englische Entsprechung, weil diese auch in VBA so zu finden ist. Der Wert eines jeden Items, kann ALLES sein: Nummern, Strings, Daten, Arrays, Ranges, Variablen, Collections, Dictionaries, ein leerer String, Nothing und Objekte. Ein Key kann kann folgendes sein: Nummer, String, Daten oder Objekt, oder eine Variable mit folgendem Inhalt: Number, String, Daten oder Objekt. Ein Array kann NICHT als Key genommen werden. Weder ein eindimensionales, noch ein mehrdimensionales Array. Es gibt 4 Möglichkeiten ein Dictionary zu befüllen.

Methode ‘.Add’

With CreateObject("scripting.dictionary")
  .Add "Key", "value"
End With

Die .Add Methode erzeugt einen Error, sollte der Key schon vorhanden sein.

With CreateObject("scripting.dictionary")
For Each vKey in Array("Banane", "Apfelsine", "Kirsche", "Mandarine", "Banane", "Zitrone", "Apfelsine")
  .Add vKey, 1
Next
End With
VBA_dict_Add_Error
VBA_dict_Add_Error

Das kann man sich zu Nutze machen, wenn man die Möglichen ‘Mehrvorkommen’ eines Keys zählen möchte. Dazu nutzt man die Methode .Exists.

    With CreateObject("scripting.dictionary")
        For Each vKey In Array("Banane", "Apfelsine", "Kirsche", "Mandarine", "Banane", "Zitrone")
            If .Exists(vKey) Then
                iCount = iCount + 1
            Else
                .Add vKey, 1
            End If
        Next
    End With
VBA_dict_Key_Exists
VBA_dict_Key_Exists

Wenn mit der .Add Methode Objekte hinzugefügt werden, werden die Eigenschaften der Objekte als Value in den Items gespeichert.

    With CreateObject("scripting.dictionary")
        .Add "range", Sheet1.Range("L1:L7")
        Debug.Print .Item("range").Rows.count
        Debug.Print .Item("range").Columns.Width
        Debug.Print .Item("range").Address
    End With
VBA_dict_Add_item_Object
VBA_dict_Add_item_Object

Methode .Item() =

Bei dieser Methode wird ein Key aus dem Array hinzugefügt, mit “value” als Inhalt der Items.

Sollte der Key schon vorhanden sein, wird KEIN Error erzeugt aber der Wert des vorhanden Items, mit dem des neuen Items überschrieben!!!!!! 

    Dim dict As Object
    Set dict = CreateObject("scripting.dictionary")
    
    For Each vKey In Array("Banane", "Apfelsine", "Kirsche", "Mandarine", "Banane", "Zitrone")
        dict.Item(vKey) = "value"
    Next
VBA_dict_Add2_item
VBA_dict_Add2_item

Objekte kann man bei dieser Methode nur mit der SET Anweisung hinzufügen. Ohne SET Anweisung wird ein Error erzeugt:

VBA_dict_Add2_item_Object_Error
VBA_dict_Add2_item_Object_Error

Mit SET sieht es so aus:

    Dim dict As Object
    Set dict = CreateObject("scripting.dictionary")
    With CreateObject("scripting.dictionary")
        Set dict.Item("range") = Sheet1.Range("L1:L7")
        Debug.Print dict.Item("range").Rows.count
        Debug.Print dict.Item("range").Columns.Width
        Debug.Print dict.Item("range").Address
    End With
VBA_dict_Add2_item_Object_SET
VBA_dict_Add2_item_Object_SET

Methode =.Item()

Bei dieser Methode wird ein Key erzeugt ohne einen Wert für das Item. Sollte der Key schon vorhanden sein, wird kein Error erzeugt. Da es keinen Wert für das Item gibt, verändert sich das Dictionary nicht.

    Dim dict As Object
    Set dict = CreateObject("scripting.dictionary")
    
    For Each vKey In Array("Banane", "Apfelsine", "Kirsche", "Mandarine", "Banane", "Zitrone")
        sDummy = dict.Item(vKey)
    Next
VBA_dict_Add4_item
VBA_dict_Add4_item

Methode das Dictionary als Objektvariable zu nutzen

Durch das Setzen des Dictionary als Objektvariable mit der SET Anweisung

Set dict = CreateObject("scripting.dictionary")
dict("Key1") = Date
dict.Item("Key2") = Date
VBA_dict_Add4_itemObjektVariable
VBA_dict_Add4_itemObjektVariable

Die nächste Frage, die uns beschäftigt ist:

Wann ist ein Key eindeutig?

Es geht um ‘case-sensitiv’ oder Groß-Kleinschreibung. Als Defaultwert (Standardeinstellung) für Dictionary gilt immer .CompareMode = 0. Das bedeutet es wird unterschieden zwischen Groß- und Kleinschreibung. Beispiel:

Sub dictCompareMethodeDefault()
    Dim dict As Object
    Set dict = CreateObject("scripting.dictionary")
        For Each vKey In Array("Banane", "banane", "BaNaNe", "BananE")
            If dict.Exists(vKey) Then
                Stop
            Else
                dict.Add vKey, 1
            End If
        Next
    Debug.Print dict.CompareMode
    Debug.Print Join(dict.Keys(), vbLf)
End Sub
VBA_dict_CompareModeDefault
VBA_dict_CompareModeDefault

Und hier, wenn man den .CompareMode von 0 auf 1 setzt (keine Unterscheidung):

Sub dictCompareMethode1()
    Dim dict As Object
    Set dict = CreateObject("scripting.dictionary")
    dict.CompareMode = 1
    For Each vKey In Array("Banane", "banane", "BaNaNe", "BananE")
        If dict.Exists(vKey) Then
            Debug.Print dict.CompareMode
            Debug.Print Join(dict.Keys(), vbLf)
            Stop
        Else
            dict.Add vKey, 1
        End If
    Next
End Sub
VBA_dict_CompareMode1
VBA_dict_CompareMode1

Von john doe

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.