Datenstrukturen

Im Gegensatz zu anderen Programmiersprachen, wie zum Beispiel C# oder Java, verfügt VBA über relativ wenige Datenstrukturen zur Verwaltung großer Datenmengen. Hier in dieser Aufstellung möchte ich diese gerne vorstellen und mit Beispielen erklären, für welche Zwecke ich diese Strukturen verwende.

Array

Das gute alte Array nutze ich immer wieder gerne, wenn es um die Verwaltung von Daten gleichen Typs geht und absehbar ist, dass die Anzahl der Elemente während der Verarbeitung konstant bleibt, bzw. wenn es aus fachlicher Sicht in Ordnung ist, dass zusätzliche Elemente einfach ans Ende des Arrays eingefügt werden. Ist die Anzahl der Elemente gleich zu Beginn der Verarbeitung klar, (zum Beispiel bei einem Array für die Verwaltung der Monatsnamen), so gebe ich die Elementenanzahl gleich bei der Deklaration mit.

Dim monatsbezeichnungen(1 To 12) As String

Ich finde es übrigens gut, dass VBA es dem Entwickler freistellt, den Arrayindex mit 0 oder 1 beginnen zu lassen. Man beginnt mit 0, wie es die meisten Programmiersprachen vorleben oder mit 1, wie es den meisten Menschen logischer erscheint:-). Ich kann es immer noch nicht verstehen, warum sich 0 als Arraystartindex in den meisten modernen Sprachen durchgesetzt hat. Aber unabhängig davon, für was man sich entscheidet, muss man speziell bei VBA dennoch aufpassen, da es selbst nicht immer stringent ist.

Mit dem Befehlt ReDim stellt VBA einen Befehl zur Verfügung, mit dem die Anzahl der Arrayelemente nachträglich verändert werden kann. Dabei sorgt das Schlüsselwort Preserve dafür, dass die bisher enthaltenen Elemente nicht gelöscht werden. Sollten wir eine Kalenderreform und dadurch einen zusätzlichen Monat bekommen, würde diese Anweisung dafür sorgen, dass das Array um ein weiteres Element erweitert wird. Die Funktion UBound liefert dabei den letzten Index des Arrays. Der Gegenspieler dazu ist die LBound-Funktion.

ReDim Preserve monatsbezeichnungen(1 to UBound(monatsbezeichnungen)+1)

Trotz dieser beschriebenen Möglichkeit stoße ich mit Arrays des Öfteren an Ihre Grenzen – und zwar immer dann, wenn ich ein neues Element nicht einfach ans Ende, sondern mitten in ein Array einsetzen oder ein Element aus dem Array löschen möchte. In beiden Fällen muss ich als Entwickler dafür sorgen, dass dabei alle nachfolgenden Elemente entweder alle um eins nach vorne (beim Löschen) oder um eins nach hinten (beim Einfügen) zu verschieben.

Da kommen nun Collections ins Spiel.

Collection

Die beiden eben beschriebenen Konstellationen lassen sich mit Collections deutlich einfacher abbilden. So muss bei der Deklaration der Collection nicht angegeben werden, aus wie vielen Elementen diese bestehen wird. Um ein neues Element einzufügen, nutzt man eine Add-Methode.


Dim aufstellung As New Collection
Dim personenObject As New Person
aufstellung.Add Item:=personenObject, After:=78

Dabei kann man festlegen, dass das neue Element an eine bestimmte Stelle einzufügen ist. Alle anderen Elemente, die darauf folgen, rutschen einfach automatisch eine Position weiter nach hinten.

Ein weiterer Vorteil von Collections gegenüber den Arrays besteht darin, dass die Collections nicht an einen bestimmten Typ von Inhalten festgelegt sind. So ist es theoretisch möglich, innerhalb einer Collection alle möglichen Inhaltstypen aufnehmen zu lassen. Natürlich sollte man damit nicht übertreiben, sonst verliert man selbst schnell den Überblick. Richtig eingesetzt, lassen sich damit komplexe baumartige Strukturen in einer Collection relativ einfach verwalten.

Aber auch die Collections haben einen Nachteil gegenüber den Arrays und den Dictionaries, den ich persönlich jedoch nicht gravierend finde. So ist es bei den Arrays sehr einfach, einem Element einen neuen Wert zuzuweisen. Bei Collection hingegen, ist es nicht ohne weiteres möglich. Hierfür muss das zu ändernde Element gelöscht und ein neues Element mit dem neuen Wert an die Position des alten Elementes hinzugefügt werden.

Nun möchte ich ein paar Wörter zum Thema Zugriff auf die Elemente verlieren. Beide Strukturen (sowohl Array als auch Collections) erlauben schnellen Zugriff auf die einzelnen Elemente mit Hilfe des Indexes, der die Position des Elementes innerhalb der jeweiligen Datenstruktur repräsentiert. In einigen Fällen jedoch, möchte man den Zugriff nicht anhand eines Indexes durchführen, sondern anhand eines fachlichen Attributes, zum Beispiel mit einer PersonenID. Für genau solche Fälle setze ich die sogenannten Dictionaries ein. Genau genommen, ist die Vergabe von individuellen Indizes auch bei Collections möglich. Die Collections bieten allerdings (mir fehlt kein Grund ein, warum es so ist) keine Methode, mit der man prüfen kann, ob ein Element mit einem bestimmten Schlüssel existiert. Als wäre es nicht genug, wird beim Versuch auf einen nicht bekannten Index zuzugreifen, auch noch ein Fehler geworfen. Daher nutze ich die Mitgabe von individuellen Schlüsseln bei Collections gar nicht.

Dictionary

Spinnen wir das Beispiel weiter, in dem wir eine große Menge Personenobjekte verwalten wollen. Jedes Personenobjekt hat neben den Attributen wie Vorname und Name auch ein Attribut PersonenID, welches jede Person eindeutig repräsentiert. Wenn diese Personenobjekte in einem Array oder in einer Collection abgelegt sind und ich das Objekt mit der Personennummer, beispielweise „1012-x-1“ heraussuchen möchte, bleibt mir bei diesen beiden Strukturen nichts anderes übrig, als sequentiell in einer Schleife alle Objekte durchzugehen und deren PersonenIDs mit der übergebenen PersonenID zu vergleichen. Sind diese identisch, kann die Schleife verlassen werden, weil das richtige Objekt gefunden wurde.

Zum einen ist es wenig effizient, wenn es sich um eine sehr große Menge an Objekten handelt und das gesuchte Objekt sich vielleicht relativ weit hinten befindet. Zum anderen benötigen wir für die Suche auch eine Schleife, was den Code nicht unbedingt schicker und schlanker macht. Der selbe Anwendungsfall mit Hilfe einer Dictionary sieht deutlich einfacher aus. Beim Hinzufügen eines neuen Elementen in die Dictionary muss ein eindeutiger Schlüsselwert angegeben werden. Hier steht es mir als Entwickler frei, einen fortlaufenden Index, oder aber einen fachlichen Schlüssel zu verwenden – in diesem ganz korrekten Fall wäre es dann die PersonenID. So kann ich dann im späteren Verlauf des Programms mit Hilfe der Methode Exists prüfen, ob es ein Personenobjekt mit dieser ID gibt und im Erfolgsfall auch direkt darauf zugreifen, ohne dass es dafür einer sequentiellen Suche und einer Schleife bedarf. Programmtechnisch muss natürlich dafür gesorgt werden, dass es keine zwei Personenobjekte mit identischen Schlüsseln (Dubletten) gibt. Anderenfalls wird beim Einfügen einer Dublette ein Fehler geworfen.

'Deklaration des Dictionary
Dim personenAufstellung As Object
Set personenAufstellung = CreateObject("Scripting.Dictionary")

key="1012-x-1"
If personenAufstellung.Exists(key) = True Then
    Msgbox "Person mit der ID " & personenAufstellung(key).getID() & " wurde gefunden"
End If
Fazit

Ich hoffe, ich habe es rüberbringen können, dass es keine eierlegende Wollmilchsau unter den Datenstrukturen gibt :-). Am besten ist es, wenn ich als Entwickler versuche, die für die jeweilige Situation am besten passende Struktur einzusetzen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.