******************************************************** * * * Vektoren und Matrizen in Excel und in VBA * * * ******************************************************** In VBA kann man arrays mit fest vorgegebener Laenge und mit dynamischer oder variabler Laenge definieren. Die Syntax ist: Arrays mit fester Laenge: Dim x(1 to 10) as double x(1) = 3.33 x(2) = 4.44 usw. Dim y(-5 to 5) as long y(-5) = -50 y(-4) = -40 usw. Dim A(1 to 3,-1 to 1) as double A(1,-1) = 7 A(1,0) = 8 A(1,1) = 9 usw. Arrays mit variabler Laenge: Etwa: n = Range("A1") und dann: Dim x() as double ReDim x(0 to n) oder Dim Vornamen() as string ReDim Vornamen(1 to n) Sind die Vornamen von 1 bis n schon vorhanden und man moechte noch 2 weitere Namen addieren: ReDim Preserve Vornamen(1 to n+2) Mit dem Befehl ReDim Vornamen(1 to n+2) wuerde man saemtliche schon vorhandenen Namen wieder loeschen. Auf einem Excel-sheet sind Vektoren und Matrizen durch 1- oder 2-dimensionale Zellbereiche gegeben. Solche Zellbereiche sind in VBA durch das Range-Objekt gegeben: Dim rg as Range Set rg = Range("A1:A5") Waehrend man bei double-, long-, bool- oder string-Variablen x einfach x = konkreter Wert schreiben kann, muss man bei Objekt-Variablen rg, und Range ist ein Objekt, immer die Syntax Set rg = konkretes Objekt benutzen, also vor dem "rg = " muss ganz am Anfang ein "Set" stehen. Schaut man sich das rg-Objekt im debug-mode im Locals- Window an, stellt man fest, dass das ein ziemlich komplexes Objekt ist. Konkrete numerische Werte findet man unter rg.Value2 . Excel-Funktionen, die als Input Vektoren oder Matrizen benoe- tigen wie etwa Correl oder MDeterm oder auch Sum, sind hin- reichend smart, so dass, wenn man sie in VBA benutzen moechte, man sowohl VBA-arrays als auch Range-Objekte als Input-Datentypen waehlen kann. Schauen wir uns dazu 2 Beispiele an: Beispiel 1: Use of Sum-Function on sheet and in VBA Beispiel 2: Use of MDeterm-Function on sheet and in VBA Schliesslich gibt es noch Excel-Funktionen, die arrays zurueck- geben, da passt das Resultat also nicht in eine Zelle, sondern man muss einen Zellbereich auswaehlen, in dem dann das Resultat reingeschrieben werden soll. Das ist der Fall fuer die 3 Matrix- Funktionen MInverse MMult Transpose Die Anwendung dieser Funktionen auf einem Excel-sheet ist etwas gewoehnungsbeduerftig, da die Eingabe mit dem gleich- zeitigen Druecken von Control-Shift-Enter abgeschlossen werden muss: Beispiel 3: Use of MInverse, MMult on sheet. Diese Funktionen lassen sich ebenfalls in VBA benutzen. Da das Resultat dieser Funktionen eine Matrix mit variabler Groesse ist, je nachdem, was der Input ist, koennte man meinen, dass die folgende Syntax (etwa fuer eine 3x3 Matrix in A1:C3) Dim Ainv() As Double Ainv = Excel.WorksheetFunction.MInverse(Range("A1:C3")) funktioniert, das tut sie aber nicht, man bekommt ein type mismatch error. Die folgende Syntax Dim Ainv() Ainv = Excel.WorksheetFunction.MInverse(Range("A1:C3")) oder aequivalent Dim Ainv() As Variant Ainv = Excel.WorksheetFunction.MInverse(Range("A1:C3")) funktioniert. Mit dem Datentyp "Variant" kann man es Excel ueberlassen, einen kompatiblen Datentyp zuzuordnen. Um etwas mehr Informationen zu bekommen, koennen wir den Code debuggen, etwa indem wir in der letzten Zeile, die mit dem "End Sub"- Statement, mit F9 einen Haltepunkt setzen und dann schauen, was im Locals-Window angezeigt wird. Dort steht aber auch nur "Ainv Variant/Double" Da MInverse eine Matrix-wertige Excel-Funktion ist, ist es naheliegend zu erwarten, dass das Resultat vom Typ "Range" ist, versuchen wir also folgendes: Dim rgAinv as Range Set rgAinv = Excel.WorksheetFunction.MInverse(Range("A1:C3")) Ok, das funktioniert so nicht, da nach "Set rgAinv = " ein konkreter Zellbereich kommen muss, machen wir also folgendes: Dim rgAinv as Range Set rgAinv = Range("A7:C9") rgAinv = Excel.WorksheetFunction.MInverse(Range("A1:C3")) Das klappt dann. Wenn man sich das Objekt rgAinv, ein Range- Objekt, im Locals-Window anschaut, sieht man, dass es sich deutlich vom Ainv Variant/Double-Objekt von oben unterscheidet. Schreiben wir schliesslich Dim Ainv2() Ainv2 = rgAinv.Value2 haben wir ein Objekt generiert, was, so wie es aussieht, mit dem Objekt Ainv von oben identisch ist.