In vielen Fällen ist es wünschswert, Listen-Elemente jeweder Art in einer bestimmten Reihenfolge vorliegen zu haben. Dazu gibt es vielfältige Möglichkeiten, die alle Vor- und Nachteile haben. Viele davon bieten sich für das nachträgliche Sortieren einer unsortierten Liste an. Ich benötige zu diesem Zweck in einer Schleife nur die Anweisung:
um, was auch immer sich in vItem befindet (String, Objekt, etc.), in dct, nach dem vKey (ein String oder numerischer Wert), im vorliegenden Fall aufsteigend sortiert, vorliegen zu haben.
Der Inhalt von dct kann am Ende der Schleife mit
weiter bearbeitet werden. Hierzu sind Kenntnisse bzgl. des Umgangs mit Scripting.Dictionaries erforderlich, die aber ganz ähnlich derer für Collections sind. Die Liste liegt also zu jedem Zeitpunkt bereits sortiert vor. Seitdem es so einfach ist, benutze ich fast nur noch sortierte Listen, zumal wenn es sich nicht um tausende von Elementen handelt, wo dann irgendwann dctAdd aus Performancegründen nicht mehr adäquat ist. Die Verwendung ist denkbar einfach:
1. Den folgenden Code in ein Standard Modul oder ein Klassen Modul kopieren:
2. Die folgenden Deklarationen in ein Standard Modul kopieren (oder, falls dctAdd nur in einer Klasse benötigt wird, ebenfalls in diese):
3. Die Referenz Microsoft Scripting Runtime dem VBA-Projekt hinzufügen - und nie mehr unsortierte Listen haben.
Anmerkungen zur Implementierung:
um, was auch immer sich in vItem befindet (String, Objekt, etc.), in dct, nach dem vKey (ein String oder numerischer Wert), im vorliegenden Fall aufsteigend sortiert, vorliegen zu haben.
Der Inhalt von dct kann am Ende der Schleife mit
weiter bearbeitet werden. Hierzu sind Kenntnisse bzgl. des Umgangs mit Scripting.Dictionaries erforderlich, die aber ganz ähnlich derer für Collections sind. Die Liste liegt also zu jedem Zeitpunkt bereits sortiert vor. Seitdem es so einfach ist, benutze ich fast nur noch sortierte Listen, zumal wenn es sich nicht um tausende von Elementen handelt, wo dann irgendwann dctAdd aus Performancegründen nicht mehr adäquat ist. Die Verwendung ist denkbar einfach:
1. Den folgenden Code in ein Standard Modul oder ein Klassen Modul kopieren:
Visual Basic-Quellcode
- Private Sub DctAdd(ByRef dct As Scripting.Dictionary, _
- ByVal vKey As Variant, _
- ByVal vItem As Variant, _
- ByVal lMode As enAddInsertMode, _
- Optional ByVal vTarget As Variant)
- ' -----------------------------------------------------
- ' "Universal" method to add an item to the Dictionary
- ' 'dct', supporting ascending and descending order,
- ' case or case insensitive key, as well as adding items
- ' before or after an existing item.
- ' Notes: - When an item with the key 'vKey' already
- ' exists, adding will just be skipped without
- ' an error.
- ' - The 'dct' dictionary is setup if yet no done
- '
- ' W. Rauschenberger, Berlin, Mar 2015
- ' -----------------------------------------------------
- Dim i As Long
- Dim dctTemp As Scripting.Dictionary
- Dim vTempKey As Variant
- Dim bAdd As Boolean
- If dct Is Nothing Then Set dct = New Dictionary
- With dct
- If .Count = 0 Or lMode = dam_sequence Then
- '~~> Very first item is just added
- .Add vKey, vItem
- Exit Sub
- Else
- '~~> Add item after the last one if appropriate
- vTempKey = .Keys()(.Count - 1)
- Select Case lMode
- Case dam_ascending
- If vKey > vTempKey Then
- .Add vKey, vItem
- Exit Sub ' Done!
- End If
- Case dam_ascendingignorecase
- If LCase(vKey) > LCase(vTempKey) Then
- .Add vKey, vItem
- Exit Sub ' Done!
- End If
- Case dam_descending
- If vKey < vTempKey Then
- .Add vKey, vItem
- Exit Sub ' Done!
- End If
- Case dam_descendingignorecase
- If LCase(vKey) < LCase(vTempKey) Then
- .Add vKey, vItem
- Exit Sub ' Done!
- End If
- End Select
- End If
- End With
- ' ----------------------------------------------
- ' Since the new key could not simply be added
- ' to the dct it must be added/inserted somewhere
- ' in between or even before the very first key.
- ' ----------------------------------------------
- Set dctTemp = New Dictionary
- bAdd = True
- For Each vTempKey In dct
- With dctTemp
- If bAdd Then
- '~~> Skip this section when already added
- If dct.Exists(vKey) Then
- '~~> Simply ignore add when already existing
- bAdd = False
- Exit Sub
- End If
- Select Case lMode
- Case dam_ascending
- If vTempKey > vKey Then
- .Add vKey, vItem
- bAdd = False ' Add done
- End If
- Case dam_ascendingignorecase
- If LCase(vTempKey) > LCase(vKey) Then
- .Add vKey, vItem
- bAdd = False ' Add done
- End If
- Case dam_addbefore
- If vTempKey = vTarget Then
- '~~> Add before vTarget key has been reached
- .Add vKey, vItem
- bAdd = True
- End If
- Case dam_descending
- If vTempKey < vKey Then
- .Add vKey, vItem
- bAdd = False ' Add done
- End If
- Case dam_descendingignorecase
- If LCase(vTempKey) < LCase(vKey) Then
- .Add vKey, vItem
- bAdd = False ' Add done
- End If
- End Select
- End If
- '~~> Transfer the existing item to the temporary dictionary
- .Add vTempKey, dct.Item(vTempKey)
- If lMode = dam_addafter And bAdd Then
- If vTempKey = vTarget Then
- ' ----------------------------------------
- ' Just add when lMode indicates add after,
- ' and the vTraget key has been reached
- ' ----------------------------------------
- .Add vKey, vItem
- bAdd = False
- End If
- End If
- End With
- Next vTempKey
- '~~> Return the temporary dictionary with the new item added
- Set dct = dctTemp
- Set dctTemp = Nothing
- Exit Sub
- End Sub
2. Die folgenden Deklarationen in ein Standard Modul kopieren (oder, falls dctAdd nur in einer Klasse benötigt wird, ebenfalls in diese):
3. Die Referenz Microsoft Scripting Runtime dem VBA-Projekt hinzufügen - und nie mehr unsortierte Listen haben.
Anmerkungen zur Implementierung:
- Wegen der vielfältigen Vorteile verwende ich (nicht nur) für meine sortierten Listen grundsätzlich ein Scripting.Dictionary. Dasselbe mit einer Collection zu realisieren wäre zwar möglich, aber etwas umstädlicher, da es keinen direkten Zugriff auf die Schlüssel gibt.
- Eine Arbeitsmappe, die auch einen umfänglichen Perfromance-Test enthält, reiche ich auf Wunsch gerne nach. Die Verwendung ist aber dermaßen einfach, dass es genauso gut möglich ist dctAdd einfach mal auf die Schnelle auszuprobieren.
- Wird der dctAdd und die Deklaration in ein Standard Modul kopiert, ist Private natürlich auf Public zu ändern.
Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „warbe“ ()