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.
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
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
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
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
Objekte kann man bei dieser Methode nur mit der SET Anweisung hinzufügen. Ohne SET Anweisung wird ein Error erzeugt:
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
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
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
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
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