Spiegeln einer Matrix oder eines Bereichs
Dieses kleine Beispiel zeigt, wie wir mit Hilfe der Einwickeltechnik aus einer gewöhnlichen Funktion mit geringem Aufwand eine benutzerdefinierte Funktion gewinnen können.
Die betrachteten Funktionen sollen die Elemente einer Matrix an einer gedachten Mittellinie spiegeln. Wir unterscheiden dabei zwei Varianten: Spiegelung an einer vertikalen Achse und Spiegelung an einer horizontalen Achse.
Horizontale Spiegelung (= Spiegelung an vertikaler Mittellinie)
Die Funktion soll die Elemente einer Matrix bezüglich einer vertikalen Mittellinie spiegeln. Die Elemente der Matrix sollen vom Typ Double sein.
Beispiel:
Aus der Matrix
1 2 3 4 5
1 2 3 4 5
wird durch Spiegelung die Matrix
5 4 3 2 1
5 4 3 2 1
Die Funktion soll keine Nebeneffekte haben, insbesondere soll die Matrix an der aufrufenden Stelle unverändert bleiben.
Lösung:
'Spiegelung an vertikaler Mittellinie, ohne Nebeneffekte
Public Function spiegelnV(ByRef a() As Double) As Double()
Dim i As Integer, j As Integer, m As Integer, n As Integer
Dim s() As Double
m = UBound(a, 1) 'Zeilenzahl
n = UBound(a, 2) 'Spaltenzahl
ReDim s(1 To m, 1 To n)
For i = 1 To m
For j = 1 To n
s(i, j) = a(i, n - j + 1)
Next j
Next i
spiegelnV = s
End Function
Beachten Sie, dass die Spiegelung nicht "in place" geschieht, d.h. nicht innerhalb des Parameterarrays a. Stattdessen wird eine Arrayvariable s deklariert, welche die gespiegelten Elemente
aufnimmt. Auf diese Weise werden Nebeneffekte vermieden. Die Funktion ist übrigens auch auf Matrizen mit gerader Spaltenzahl anwendbar.
Leider ist die oben stehende Funktion so nicht als benutzerdefinierte Funktion verwendbar. Es ist also nicht möglich, dass der Excel-Benutzer damit Bereiche eines Arbeitsblatts spiegelt.
Allerdings können wir mithilfe der Einwickeltechnik sehr leicht eine Funktion schreiben, welche dies erlaubt:
'Spiegelung eines Bereichs an vertikaler Mittellinie
Public Function spiegelnV_UDF(ByVal r As Range) As Double()
spiegelnV_UDF = spiegelnV(RangeToDblArray(r))
End Function
Der Trick besteht darin, den Parameter r mit Hilfe der Funktion RangeToDblArray in ein Double-Array zu verwandeln, das von der Funktion spiegelnV als Input akzeptiert wird. Die Funktion
RangeToDblArray ist bereits aus dem Skript und anderen Beispielen bekannt, sei aber trotzdem noch einmal aufgeführt:
Public Function RangeToDblArray(ByVal r As Range) As Double()
Dim d() As Double
ReDim d(1 To r.Cells.Rows.Count, 1 To r.Cells.Columns.Count)
Dim i As Integer, j As Integer
For i = 1 To UBound(d, 1)
For j = 1 To UBound(d, 2)
d(i, j) = CDbl(r.Cells(i, j).Value)
Next j
Next i
RangeToDblArray = d
End Function
Vertikale Spiegelung (= Spiegelung an horizontaler Mittellinie)
Die Fragestellung ist mit der obigen verwandt. Wir wollen die Matrix nun an einer horizontalen
Achse spiegeln.
Beispiel:
Aus der Matrix
1 1 1 1 1
2 2 2 2 2
wird durch Spiegelung die Matrix
2 2 2 2 2
1 1 1 1 1
Lösung:
'Spiegelung an horizontaler Mittellinie, ohne Nebeneffekte
Public Function spiegelnH(ByRef a() As Double) As Double()
Dim i As Integer, j As Integer, m As Integer, n As Integer
Dim s() As Double
m = UBound(a, 1) 'Zeilenzahl
n = UBound(a, 2) 'Spaltenzahl
ReDim s(1 To m, 1 To n)
For i = 1 To m
For j = 1 To n
s(i, j) = a(m - i + 1, j)
Next j
Next i
spiegelnH = s
End Function
Wie im obigen Fall, gewinnen wir leicht durch Einwickeln eine UDF zum Spiegeln eines Bereichs:
Public Function spiegelnH_UDF(ByVal r As Range) As Double()
spiegelnH_UDF = spiegelnH(RangeToDblArray(r))
End Function