vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Brandneu! sevEingabe v3.0 - Das Eingabecontrol der Superlative!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2018
 
zurück
Rubrik: Variablen/Strings · Array/ArrayList   |   VB-Versionen: VB2005, VB200817.06.08
Klasse für nicht-nullbasierte Arrays

Manchmal sind nicht-nullbasierte Arrays nützlich. Diese Klasse bietet dafür einen Vorschlag.

Autor:   Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  8.117 
ohne HomepageSystem:  Win2k, WinXP, Vista, Win7, Win8, Win10 Beispielprojekt auf CD 

In VB.Net sind die System.Arrays stets null-basiert. Falls man den Array-Index nur als eine Zugriffshilfe auf die einzelnen Array-Elemente^betrachtet, ist das keine besondere Einschränkung.

Unter bestimmten Umständen kann es aber nützlich sein, wenn dem Array-Index auch eine inhaltliche Bedeutung zuzuordnen ist.

Wertet man z.B. jahresbezogene Zeitreihen aus, die von 'ErstesJahr' (z.B. 1970) bis 'LetztesJahr' (z.B. 2008) erhoben worden sind, ist es zweckmäßig, die Daten in einem Array aufzubewahren, dessen Dimension von 1970 bis 2008 läuft.

Der Array-Index besitzt in diesem Fall zugleich die Bedeutung: Jahreszahl.

Die generische Klasse cArrayXToY erlaubt die Erstellung von ein- und mehrdimensionalen Arrays, deren Dimensions-Untergrenze(n) nicht 0 sein müssen, sondern beliebig wählbar sind. Für die Obergrenze jeder Dimension gilt, dass sie >= Untergrenze sein muß.

Die Erstellung von Instanzen der Klasse erfolgt durch den Konstruktor (New), der zugleich den Datentyp des Array, die Zahl der Dimensionen und die Unter- und Obergrenzen jeder Dimension festlegt. (Vgl. Kommentarzeilen und Anwendungsbeispiel). Zusätzlich werden Hilfswerte für den effizienten Zugriff erstellt.

Die Grenzen einer Array-Dimension können durch die Funktionen lbd/ubd abgefragt werden (1. Dimension = 0!).
(Bitte beachten Sie, dass die Klasse nur für die integrierten numerischen Datentypen und den Datentyp String getestet worden ist. Bei der Verwendung von Klassen oder Strukturen als Array-Elemente sind ggf. zusätzliche Gesichtspunkte zu berücksichtigen.)

Die Klasse löst sowohl bei der Array-Deklaration (Konstruktor) als auch beim Array-Zugriff Ausnahmen aus, falls Dimensionen oder Indizes nicht plausibel sind.

Auf die Implementierung der Methoden für Redim(Preserve), Clone und CopyTo ist der Einfachheit halber verzichtet worden. Die Anwendung solcher Funktionen auf nicht-nullbasierte Arrays ist ohnehin meist weniger empfehlenswert. Übersichtlicher ist es, das Zielarray (ggf. mit den Grenzen) explizit zu erstellen und die gewünschten Elemente in Schleifen sukzessive aus dem Quellarray zu übertragen.

Hinweis für VB6-Umsteiger:
Wenn Sie sich jetzt wundern, liegen Sie richtig. Diese Einschränkung gab es in VB6-Arrays nicht. Auch in den aktuellen VB-Versionen ist es zwar möglich, ein Array durch Dim arr(x to y) zu deklarieren. Aber: x muss dabei stets 0 sein.

Nicht-nullbasierte Arrays stehen nur noch im Rahmen der COM.Interop-Kompatibilität zur Verfügung.

Während der Umstell-Phase von VB6-Programmen kann dies für Testzwecke nützlich sein. (vgl.  Nicht-nullbasierte Arrays in VB.NET)

Vorsicht ist bei der Verwendung des Upgrade-Assistenten geboten.

Die VB6-Dimensionierung:

Dim x(90 to 100, 90 to 100, 90 to 100)

wird wie folgt umgestellt:

' UPGRADE_WARNING: 
' Lower bound of array x was changed from 90,90,90 to 0,0,0. 
Dim x(100, 100, 100) As Object

Die Klasse cArrayXToY

''' <summary>
''' generische Klasse zur Verwendung eines gekapselten 1D-Array
''' als nicht-nullbasiertes (ggf. auch mehrdimensionales) Array
''' </summary>
''' <typeparam name="EntryType">numerischer Typ oder String</typeparam>
Public Class cArrayXToY(Of EntryType)
 
  ' Struktur für Daten einer Arraydimension
  Structure Limit
    Dim ug As Integer         ' Untergrenze
    Dim og As Integer         ' Obergrenze
    Dim elemente As Integer   ' Länge
  End Structure
 
  Dim gLimits() As Limit     ' Dimensionsgrenzen des Array
  Dim gDimFak() As Integer   ' Hilfs-Faktoren zur Indexberechnung
 
  ' das gekapselte System.Array 
  ' (-->null-basiert, ein-dimensional)
  Dim gArray() As EntryType
  ''' <summary>
  ''' Konstruktor (incl. Vereinbarung der Dimensionsgerenzen)
  ''' </summary>
  ''' <param name="Limits">Dimensionsgrenzen: ug1, og1, ug2, og2, ...</param>
  Public Sub New(ByVal ParamArray Limits() As Integer)
    ' Array auf 'Nichts' setzen
    gArray = Nothing
 
    ' Limits überprüfen
    If UBound(Limits) > 20 Or UBound(Limits) < 1 Then
      Throw New ArgumentException
    End If
    If UBound(Limits) Mod 2 <> 1 Then
      Throw New ArgumentException
    End If
 
    ' Überprüfung der Limits fortsetzen und speichern
    ReDim gLimits(Limits.Length \ 2 - 1)
    Dim j As Integer = -1, l As Integer = 1
    For i As Integer = 0 To UBound(Limits) - 1 Step 2
      j += 1
      gLimits(j).ug = Limits(i)
      gLimits(j).og = Limits(i + 1)
      If gLimits(j).ug > gLimits(j).og Then
        Throw New ArgumentException
      End If
      gLimits(j).elemente = _
      gLimits(j).og - gLimits(j).ug + 1
      l *= gLimits(j).elemente
    Next i
 
    ' gekapseltes 1D-Array in der angeforderten Größe dimensionieren
    ReDim gArray(l - 1)
 
    ' Zu überspringende Elementzahl pro Indexwert einer Dimension
    ' => Multiplikation der Elementzahl aller höheren Dimensionen
    ReDim gDimFak(UBound(gLimits))
    For i As Integer = 0 To UBound(gLimits)
      gDimFak(i) = 1
      For k As Integer = i + 1 To UBound(gLimits)
        gDimFak(i) *= gLimits(k).elemente
      Next k
    Next i
  End Sub
  ''' <summary>
  ''' Integrierte LBOUND-Funktion: Untergrenze der Dimension
  ''' </summary>
  ''' <param name="Dimension">Dimension?</param>
  ''' <returns>Untergrenze</returns>
  Public Function Lbd(Optional ByVal Dimension As Integer = 0) As Integer
    If IsNothing(gArray) Then
      Throw New NullReferenceException
    End If
 
    If Dimension > _
    Microsoft.VisualBasic.UBound(gLimits) Then
      Throw New RankException
    End If
 
    Return gLimits(Dimension).ug
  End Function
  ''' <summary>
  ''' Integrierte UBOUND-Funktion: Obergrenze der Dimension
  ''' </summary>
  ''' <param name="Dimension">Dimension?</param>
  ''' <returns>Obergrenze</returns>
  Public Function Ubd( _
    Optional ByVal Dimension As Integer = 0) As Integer
 
    If IsNothing(gArray) Then
      Throw New NullReferenceException
    End If
 
    If Dimension > Microsoft.VisualBasic.UBound(gLimits) Then
      Throw New RankException
    End If
 
    Return gLimits(Dimension).og
  End Function
  ''' <summary>
  ''' Standardeigenschaft: Zuweisung oder Abfrage 
  ''' eines Arrayelements
  ''' </summary>
  ''' <param name="ind1">Index 1. Dimension</param>
  ''' <param name="Indices">Indices weiterer Dimensionen</param>
  ''' <value>zuzuweisender Wert</value>
  ''' <returns>abgefragter Wert</returns>
  Default Public Property Value(ByVal ind1 As Integer, _
    ByVal ParamArray Indices() As Integer) As EntryType
 
    ' Nicht wundern: Da eine Standardeigenschaft nicht 
    ' nur ein ParamArray als Parameter besitzen darf, 
    ' ist der erste Array-Index 'ausgelagert' worden
    Get
      If IsNothing(gArray) Then
        Throw New NullReferenceException
      End If
      Return gArray(Get1D_Index(ind1, Indices))
    End Get
    Set(ByVal value As EntryType)
      If IsNothing(gArray) Then
        Throw New NullReferenceException
      End If
      gArray(Get1D_Index(ind1, Indices)) = value
    End Set
  End Property
  Private Function Get1D_Index(ByVal ind1 As Integer, _
    ByVal ParamArray Indices() As Integer) As Integer
 
    ' Umrechnung der Indices auf das korrespondierende 
    ' Element des internen eindimensionalen Arrays
 
    ' Indices auf Gültigkeit prüfen
    Dim i As Integer
    If UBound(Indices) <> UBound(gLimits) - 1 Then
      Throw New RankException
    End If
    If ind1 < gLimits(0).ug Or ind1 > gLimits(0).og Then
      Throw New IndexOutOfRangeException
    End If
    For i = 0 To UBound(Indices)
      If Indices(i) < gLimits(i + 1).ug Or _
      Indices(i) > gLimits(i + 1).og Then
        Throw New IndexOutOfRangeException
      End If
    Next i
 
    ' Berechnung des 1D-Index unter Verwendung 
    ' der dimensionalen Index-Multiplikatoren
    Dim ind As Integer = 0 '= ind1 * fak(0)
    ind = gDimFak(0) * (ind1 - gLimits(0).ug)
    For i = 1 To UBound(gLimits)
      ind += (gDimFak(i) * (Indices(i - 1) - gLimits(i).ug))
    Next i
 
    Return ind
  End Function
End Class

Anwendungsbeispiel: ArrayXToY_Demo

Private Sub ArrayXtoY_Demo()
  ' Die generische Klasse 'ArrayXtoY erlaubt '
  ' die Verwendung verschiedener Datentypen
 
  ' Erstellung Vier-dimensionaler Arrays:
  Dim str As New cArrayXToY(Of String) _
  (-1, 5, -2, 6, -3, 7, -8, -4)
  Dim dbl As New cArrayXToY(Of Double) _
  (-1, 5, -2, 6, -3, 7, -8, -4)
  Dim shrt As New cArrayXToY(Of Short) _
  (-1, 5, -2, 6, -3, 7, -8, -4)
 
  Dim z As Integer
  z = -1
  For i As Integer = str.Lbd(0) To str.Ubd(0)
    For k As Integer = str.Lbd(1) To str.Ubd(1)
      For l As Integer = str.Lbd(2) To str.Ubd(2)
        For m As Integer = str.Lbd(3) To str.Ubd(3)
          z += 1
          ' Zuweisung auf akt. Array-Element
          str(i, k, l, m) = CStr(z)
          dbl(i, k, l, m) = z  ' Erweiterungskonv.
          shrt(i, k, l, m) = CShort(z) ' expl. Konv.
        Next m
      Next l
    Next k
  Next i
 
  z = -1
  For i As Integer = dbl.Lbd(0) To dbl.Ubd(0)
    For k As Integer = dbl.Lbd(1) To dbl.Ubd(1)
      For l As Integer = dbl.Lbd(2) To dbl.Ubd(2)
        For m As Integer = dbl.Lbd(3) To dbl.Ubd(3)
          z += 1
          ' Prüfabfrage des akt. Array-Elements
          If str(i, k, l, m) <> CStr(z) Then Stop
          If dbl(i, k, l, m) <> z Then Stop
          If shrt(i, k, l, m) <> z Then Stop
        Next m
      Next l
    Next k
  Next i
End Sub

Dieser Tipp wurde bereits 8.117 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2018 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel