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