Home > Artikel > Ausgabe 8/2015 > Arrays als Funktionsergebnis

Arrays als Funktionsergebnis

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Eine Sub-Prozedur führt unter VBA eine Aktion durch, eine Funktion möglicherweise auch, doch wichtiger ist in der Regel das berechnete Ergebnis, welches sie dem Aufruf zurückgibt. Fast immer handelt es sich dabei um einen bestimmten gesuchten Wert. Gelegentlich erwartet die aufrufende Prozedur aber auch eine Menge von Rückgabedaten. Hier kommen Arrays ins Spiel.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1508_Array.accdb.

Multiple Ergebnisse

Gerade in der Datenbankprogrammierung ist die Rückgabe von Ergebnissen, die mehr, als einen Wert enthalten, trivial. Nur kommen hier zur Auswertung gewöhnlich Datenbankobjekte zum Einsatz, deren Hauptprotagonist das Recordset ist.

So gibt die Methode OpenRecordset von DAO nicht nur eine Serie von Daten zurück, sondern sogar eine zweidimensionale: in der einen Dimension die Spalten, also Felder, eines Datensatzes, in der anderen die Datensätze selbst.

An die Zellen dieser zweidimensionalen Wertemenge gelangt man dann über spezielle Methoden des Objekts, statt über Indizes, wie das bei Arrays der Fall ist. Auf der einen Seite ist dies praktisch, auf der anderen Seite verlangt es mehr Programmierung.

Hierzu ein Beispiel. Sie möchten den Wert der Zelle einer Adressentabelle ermitteln, sei es etwa die dritte Spalte des vierzehnten Datensatzes. Unter Excel könnte das Arbeitsblatt nun tatsächlich über Koordinaten abgefragt werden:

Debug.Print WorkSheet.Cells(13,2)

Bei einem Recordset ist das nicht direkt möglich. Hier sähe die Routine so aus:

Set rs = CurrentDb. _

     OpenRecordset("tblAdressen")

rs.Move 13

Debug.Print rs(2).Value

Hier haben wir eine Zeile mehr Code und die Übersicht ist geringer, weil die Koordinaten auf unterschiedliche Zeilen aufgeteilt sind.

Befänden sich alle Adressdaten in einem Array, so könnte über zwei Indizes auf die Zelle zugegriffen werden. Immerhin hält DAO dafür eine eigene Methode bereit:

Set rs = CurrentDb. _

     OpenRecordset("tblAdressen")

V = rs.GetRows

Debug.Print V(2,13)

GetRows verwandelt nämlich die Datensätze eines Recordsets in ein zweidimensionales Array, wobei dieses als Variant deklariert sein muss und die einzelnen Elemente darin ebenfalls diesen Datentyp aufweisen.

Wollten Sie dieses Array als Ergebnis einer Funktion zurückgeben, dann käme diese Routine infrage:

Function TabellenArray() As Variant

     Dim rs As DAO.Recordset

     Set rs = CurrentDb. _

         OpenRecordset("tblAdressen")

     TabellenArray = rs.GetRows

End Function

Aber schauen wir uns den Umgang mit Arrays in Funktionen einmal etwas genereller an.

Array mit Elementen füllen

Es muss nicht eine Funktion sein, wenn ein Array in einer Sub-Prozedur mit Werten gefüllt werden soll. Sie können ein Array der Prozedur auch als Argument übergeben. Die folgende Routine vollzieht das:

Sub FillArray(cnt As Long, _

               arr As Variant)

     Dim i As Long

     ReDim arr(cnt)

     For i = 0 To cnt

         arr(i) = "Element " & i

     Next i

End Sub

Für den Aufruf der Prozedur könnte man dies schreiben:

Dim arr As Variant

FillArray 4, arr

Die Prozedur nimmt als Parameter die Zahl an Elementen in der Variablen cnt entgegen und dimensioniert das Array arr dann entsprechend, um es schließlich in einer Schleife mit Werten zu besetzen. Die Auswertung des so erhaltenen Arrays erfolgte ebenfalls in einer Schleife:

For i = 0 To UBound(arr)

     Debug.Print arr(i)

Next i

Das erstaunliche an der Sache ist, dass in der aufrufenden Prozedur das Array gar nicht als solches deklariert wurde, sondern als Variant. Der Datentyp der Variablen arr steht zu diesem Zeitpunkt also noch gar nicht fest.

Dennoch lässt sich die Redim-Anweisung auf den Variant anwenden, wodurch VBA ihn automatisch zu einem Array macht, dessen Elemente ebenfalls vom Typ Variant sind. Deshalb kann in der Folge die Funktion UBound zum Ermitteln der Grenzen des Arrays angewandt werden.

In dieser Version ist die vorherige Deklaration einer Variablen, die der Prozedur übergeben wird, zwingend. Anders sieht der Fall aus, wenn, wie in Listing 1, eine Funktion fuArray zum Einsatz kommt, die als Rückgabe direkt ein Array herausrückt.

Sub Test()

     Dim arr As Variant

     arr = fuArray(4)

     For i = 0 To UBound(arr)

         Debug.Print arr(i)

     Next i

End Sub

Function fuArray(cnt As Long) As String()

     Dim i As Long

     Dim arr() As String

     

     ReDim arr(cnt)

     For i = 0 To cnt

         arr(i) = "Element " & i

     Next i

     fuArray = arr

End Function

Listing 1: String-Array als Ergebnis einer Funktion fuArray

Als Parameter wird ihr die gewünschte Zahl von Elementen in cnt übergeben. Innerhalb der Funktion wird ein eigenes Array arr angelegt, dimensioniert und in der Schleife gefüllt. Dieses Array wird am Schluss der Funktion als Ergebnis überreicht. Dabei ist das Resultat von vorn herein nicht als Variant deklariert, sondern als String-Array, was durch die Klammern deutlich wird: String().

Der Aufwand ist in der Test-Routine nicht geringer, als bei der besprochenen Sub-Prozedur. Auch hier muss das Ergebnis der Funktion in einer Variablen arr zwischengespeichert werden, um es in einer Schleife zu enumerieren.

Aber möchte man nur einen Wert der Ergebnismenge abfragen, so reicht in diesem Fall bereits eine Zeile:

Debug.Print fuArray(4)(3)

-> "Element 3"

Eine Variable zum Zwischenspeichern entfällt. Daraus leitet sich ab: Die Deklaration einer Funktion führt Imgrunde zur Deklaration einer Variablen selben Namens und desselben Typs.

Der Vollständigkeit halber hier noch eine Routine, die statt des Arrays eine Collection heranzieht. In Listing 2 wird die Funktion fuCollection per Set-Anweisung direkt als neue Collection deklariert und angelegt. Die Elemente, die sie aufnimmt, werden zusätzlich und optional mit einem Key versehen, der sich aus dem Schleifenzähler i und dem String "i" zusammensetzt.

Sub Test()

     Dim itm As Variant

     For Each itm In fuCollection(4)

         Debug.Print itm

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!