Suggesties | ArrayList |
1. Wat is een ArrayList ? 2. Waarvoor een ArrayList ? 3. Achtergrond van de ArrayList 4. Maak een ArrayList 4.1 Early binding 4.1.1 Local scope 4.1.2 Private scope 4.1.3 Public scope 4.2 Late binding 4.2.1 Local scope 4.2.2 Private scope 4.2.3 Public scope 5. Vul een ArrayList 5.1 Afzonderlijke elementen 5.1.1 Methode Add 5.1.2 Methode Insert 5.2 Een groep elementen 5.2.1 Methode AddRange 5.2.2 Methode InsertRange 5.3 Soorten Items 5.3.1 lege tekstreeks 5.3.2 gewone tekstreeks 5.3.3 niet-afdrukbaar teken 5.3.4 getal 5.3.5 datum 5.3.6 1-dimensionele array 5.3.7 meer-dimensionele array 5.3.8 object 5.3.9 controls in Userform 5.3.10 ActiveX controls 5.3.11 alle werkbladen 6. De omvang van een ArrayList 7. Controle of een item voorkomt 8. Controle op item-positie 9. Lezen van elementen 9.1 één element 9.2 opeenvolgende elementen 9.3 alle elementen 10 Wijzig een element 11 Sorteren van elementen 11.1 Oplopend sorteren 11.2 Aflopend sorteren 11.3 Sorteer Arrays 12 Verwijder elementen 12.1 één element op inhoud 12.2 één element op index 12.3 opeenvolgende elementen 12.4 alle elementen 13. Kopie van een ArrayList 14. Trefwoorden |
Een ArrayList in VBA is een verzamelobject: je kunt er allerlei verschillende zaken in opbergen: getallen, teksten, datums, arrays, ranges, variabelen en objecten. VBA heeft verschillende andere mogelijkheden om gegevens op te slaan: - een dictionary - een collection - een array variabele - een ActiveX ComboBox - een ActiveX ListBox - een Userform control ComboBox - een Userform control ListBox - een sortedlist De keuze voor een van deze methoden is afhankelijk van het te bereiken doel. In deze pagina wordt geen poging gedaan al deze methoden met elkaar te vergelijken. We beperken ons tot een bespreking van de mogelijkheden van de ArrayList. Geen van de andere 'verzamel' methoden zoals Collecten, Array of Dictionary heeft een sorteermethode. De sorteermethode van de ArrayList is (naast de 'sortedlist') de enige mij bekende VBA-sorteermethode. Deze sorteermethode is erg snel. Dat kan een argument zijn om juist van een ArrayList gebruik te maken.
In plaats van gegevens te bewerken in een Excel-werkblad, een Word Document, een Powerpointpresentatie, doe je dat in het werkgeheugen. Daarvoor hoeft bijv. geen scherm ververst te worden, berekeningen uitgevoerd te worden, waardoor de ArrayList snel is.
De ArrayList is onderdeel van de bibliotheek System.Collections. Die bevindt zich in het bestand ....\WINDOWS\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb of in een vergelijkbare directory Je kunt via de VBEditor een aktieve verbinding leggen naar dit bestand door mscorlib.dll bij de Referenties aan te vinken (Extra/referenties... of Tools/References..) Als je een bestand waarin je gebruik maakt van een ArrayList verspreidt, wordt meteen ook die verbinding naar deze bibliotheek meeverspreid. In VBA kun je op twee verschillende manieren die referentie maken ThisWorkbook.VBProject.References.AddFromFile "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb" ThisWorkbook.VBProject.References.AddFromguid "{BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}", 2, 4 Je kunt de code ook pas een verbinding laten leggen op het moment dat je de ArrayList nodig hebt ('late binding'). Daarvoor gebruik je dan deze VBA code: createobject("System.Collections.ArrayList")
Dat is afhankelijk van: - de manier waarop je naar de bibliotheek van de ArrayList wil verwijzen: 'early binding' of 'late binding' - de 'scope' van de ArrayList: wil je hem in 1 procedure of meer procedures gebruiken:'local scope','private scope','public scope'
zonder toewijzing aan een variabele: With new ArrayList .Add "aa1"
end withdim a_00 as New ArrayList a_00.Add "aa1" set a_00 = New ArrayList a_00.add "aa1" dim a_00 as Object set a_00= new ArrayList a_00.add "aa1" dim a_00 as ArrayList set a_00= new ArrayList a_00.add "aa1" Dan dien je altijd met een variabele te werken. Die variabele moet je eerst in het declaratiegebied van de codemodule declareren. Je kunt het gegevenstype van de variabele voor een ArrayList declareren als Object, ArrayList of Variant. Omdat de Variant het default gegevenstype is, kun je de specificatie van dit gegevenstype ook achterwege laten. In het declaratiedeel van de codemodule zet je Dim a_00 Private a_00 Dim a_00 as Variant Private a_00 as Variant Dim a_00 as Object Private a_00 as Object Dim a_00 as ArrayList Private a_00 as ArrayList Set a_00 = New ArrayList Dim a_00 As New ArrayList Private a_00 as New ArrayList Als je een ArrayList toegankelijk wil maken voor alle procedures (macro's of funkties) in het werkboek, Userform, Macromodule of Classmodule maak je gebruik van Public Scope. Dan dien je altijd met een variabele te werken.
Vervolgens moet je aan de variabele een nieuwe instantie van de ArrayList toewijzen. Wanneer je gebruik maakt van 'early binding' kan dat heel compact in één keer met deze code in het declaratiegebied. Public a_00 As New ArrayList
Je kunt het gegevenstype van de variabele voor een ArrayList declareren als Object, ArrayList of Variant. Omdat de Variant het default gegevenstype is, kun je de specificatie van dit gegevenstype ook achterwege laten. In het declaratiegebied Public a_00 Public a_00 as Variant Public a_00 as Object Public a_00 as ArrayList Wijs een nieuwe instantie van de ArrayList toe aan de gedeclareerde variabele. set a_00 = new ArrayList
zonder toewijzing aan een variabele: With CreateObject("System.Collections.ArrayList") .Add "aa1"
end withset a_00 = CreateObject("System.Collections.ArrayList") a_00.Add "aa1" Dan dien je altijd met een variabele te werken. Die variabele moet je eerst in het declaratiegebied van de codemodule declareren. Je kunt het gegevenstype van de variabele voor een ArrayList declareren als Object of Variant. Omdat de Variant het default gegevenstype is, kun je de specificatie van dit gegevenstype ook achterwege laten. Vervolgens wijs je in een procedure (macro of funktie) een nieuwe instantie van de ArrayList toe aan de gedeclareerde variabele. In het declaratiedeel van de codemodule Dim a_00 Private a_00 Dim a_00 as Variant Private a_00 as Variant Dim a_00 as Object Private a_00 as Object Set a_00 = CreateObject("System.Collections.ArrayList") Als je een ArrayList toegankelijk wil maken voor alle procedures (macro's of funkties) in het werkboek, Userform, Macromodule of Classmodule maak je gebruik van Public Scope. Dan dien je altijd met een variabele te werken. De declaratie van die variabele dient te staan in het declaratiegebied van een macromodule (dus niet in de codemodule van een userform, werkblad, het werkboek of een klassemodule). In welke macromodule de declaratie staat maakt niet uit. Het gegevenstype voor de ArraylList kan zijn Variant of Object. Omdat er nog geen verbinding is gelegd met de ArrayList-bibliotheek kun je het gegevenstype 'ArrayList' niet gebruiken. In een procedure (macro of funktie) wijs je een nieuwe instantie van de ArrayList toe aan de gedeclareerde variabele. In het declaratiedeel van de codemodule van een macromodule Public a_00 Public a_00 as object Public a_00 as object set a_00 = CreateObject("System.Collections.ArrayList") Voor het vervolg in deze pagina zal ik voor de overzichtelijkheid alleen gebruikmaken van de With ... End With methode in een 'late binding' situatie. De inhoud van een item kan van alles zijn: getallen, teksten, datums, arrays, ranges, variabelen, collections, dictionaries, een lege tekenreeks, niets en objecten Je kunt aan een ArrayList afzonderlijke items toevoegen of een groep van items. Ook kun je aangeven waar de nieuwe items in de ArrayList geplaatst moeten worden.
With CreateObject("System.Collections.ArrayList") .Add "inhoud"
End With.Add New Collection .Add 123 .Add Date .Add Array("rood", "wit", "groen") Houd er rekening mee dat het eerste element in de ArrayList het indexnummer 0 heeft. With CreateObject("System.Collections.ArrayList") .Add "aa1"
End With.Add "aa2" .Add "aa4" .Insert 2,"aa3" Voorwaarde is wel dat die items in een speciale 'Array' staan. Daarvoor moet je gebruik maken van de Queue, die onderdeel is van dezelfde bibliotheek als de ArrayList. Je moet dus eerst de elementen in zo'n Queue zetten. De instructie die je daarvoor gebruikt is '.Enqueue' (zoals .Add bij de ArrayList). Vervolgens kan deze Queue aan de ArrayList worden toegevoegd. Ook hier heb je de keus de Queue achteraan de ArrayList te plaatsen of op een vooraf bepaalde plek. De methode .AddRange plaatst items altijd achter het laatste element van de ArrayList. Set q_00 = CreateObject("System.Collections.Queue") q_00.Enqueue "een" q_00.Enqueue "twee" With CreateObject("System.Collections.ArrayList") .Add "aa1"
End With.Add "aa2" .Add "aa3" .AddRange q_00 Houd er rekening mee dat het eerste element in de ArrayList het indexnummer 0 heeft. Set q_00 = CreateObject("System.Collections.Queue") q_00.Enqueue "vier" q_00.Enqueue "vijf" With CreateObject("System.Collections.ArrayList") .Add "aa1"
End With.Add "aa2" .Add "aa3" .InsertRange 1, q_00 De inhoud van een item kan van alles zijn: getallen, teksten, datums, arrays, ranges, variabelen, collections, dictionaries, een lege tekenreeks, niets en objecten Hieronder een aantal voorbeelden van items met verschillende soorten inhoud. With CreateObject("System.Collections.ArrayList")
.Add vbNullString
End With.Add "" With CreateObject("System.Collections.ArrayList")
.Add "abcde"
End With.Insert 0, "fghi"
With CreateObject("System.Collections.ArrayList")
.Add vbTab
End With.Insert 0, vbLf With CreateObject("System.Collections.ArrayList")
.Add 12345
End With.Insert 1, RGB(23, 45, 678) ' typename: Integer
' typename: Long
With CreateObject("System.Collections.ArrayList")
.Add Date
End With.Add CDate("23-04-2012") .Insert 2, DateSerial(2013, 10, 12)
With CreateObject("System.Collections.ArrayList")
.Add Array("aa1", "aa2", "aa3")
End With.Add Split("bb1_cc1_dd1", "_") .Insert 1,Array("aa1", "aa2", "aa3")
With CreateObject("System.Collections.ArrayList")
ReDim sn(6, 10)
End With.Add sn .Insert 1, sn With CreateObject("System.Collections.ArrayList")
.Add Range("A1:K10")
End With.Insert 1, Range("A1:K10")
With CreateObject("System.Collections.ArrayList")
For Each it In Controls
End With.Add it
Next
With CreateObject("System.Collections.ArrayList")
For Each it In Sheets("sheet1").OLEObjects
End With.Add it
Next
With CreateObject("System.Collections.ArrayList")
For Each sh In Sheets
End With.Add sh
Next.Insert 1, sh
With CreateObject("System.Collections.ArrayList")
For Each sh In Sheets
End With.Add sh
Next.Insert 1, sh msgbox .count
De eigenschap .Contains geeft aan of een item in een ArrayList voorkomt: With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End WithIf Not .contains(it) Then .Add it
NextMet gebruik van de eigenschap .Contains kun je in de ArrayList een lijst van unieke items samenstellen ( zie voorbeeld hierboven ).
Het eerste argument is de waarde waarnaar je wil zoeken, het tweede argument is de positie waarná je wil zoeken: With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa5", "aa6")
End WithIf Not .contains(it) Then .Add it
Nextmsgbox .IndexOf("aa4", 0) Als het item wel bestaat is het resultaat het indexnummer (volgnummer) van het item in de ArrayList. Als je wil nagaan of een item vóór of ná een bepaald indexnummer voorkomt gebruik je dat indexnummer als het tweede argument: msgbox .IndexOf("aa4", 5) ' indexnummer als het na het 5e element voorkomt
Omdat identieke items meer dan eens in een ArrayList kunnen voorkomen kun je ook nagaan op welke positie een bepaalde waarde het laatst voorkomt in de ArrayList.Gebruik daarvoor de eigenschap .LastIndexOf("aa11"): With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Nextmsgbox .LastIndexOf("aa2")
With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.add array("P_01","P_02","P_03","P_04") .add "last item" msgbox .Item(0) msgbox .Item(.count-1) msgbox .Item(6)(3) ' het eerste item
' het laatste item ' het 4e element uit de array in het 6e item in de ArrayList
With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
NextSet st = .getrange(2, 4) for each it in st msgbox it
next' haal 4 elementen uit de reeks vanaf index 2 (= 3e item)
Afhankelijk van de inhoud kun je daar methodes als 'join', 'filter' en 'replace' op loslaten. With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Nextsn=.toarray msgbox join(sn,vblf) Horizontaal: With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Nextsheet1.cells(1).resize(,.count)=.toarray With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Nextsheet1.cells(1).resize(.count)=application.transpose(.toarray) Het te wijzigen item benader je met behulp van het indexnummer. With CreateObject("System.Collections.ArrayList") For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.item(3)="aa20" .item(4)=12 .item(5)=Date .item(2)=array(1,2,3,4,5)
Voorwaarde is natuurlijk wel dat de elementen te sorteren zijn: de waarden moeten bestaan uit tekst of getallen (geen arrays of objecten). De ArrayList evalueert zelf of er sprake moet zijn van een numerieke sortering of een tekstsortering. Een mengeling van gegevenstypen leidt tot een foutmelding. tekstsortering With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.Sort sn = .toarray MsgBox Join(sn, vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array("12", "112", "2", "34", "305", "302")
End With.Add it
Next.Sort sn = .toarray MsgBox Join(sn, vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array(12, 112, 2, 34, 305, 302)
End With.Add it
Next.Sort sn = .toarray MsgBox Join(sn, vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", 12, 112, "aa3", "aa2", "aa6")
End With.Add it
Next.Sort ' foutmelding
Voorwaarde is natuurlijk wel dat de elementen te sorteren zijn: de waarden moeten bestaan uit tekst of getallen (geen arrays of objecten). De ArrayList evalueert zelf of er sprake moet zijn van een numerieke sortering of een tekstsortering. Een mengeling dan gegevenstypen leidt tot een foutmelding. tekstsortering With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.Sort .Reverse MsgBox Join(.toarray, vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array("12", "112", "2", "34", "305", "302")
End With.Add it
Next.Sort .Reverse MsgBox Join(.toarray, vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array(12, 112, 2, 34, 305, 302)
End With.Add it
Next.Sort .Reverse MsgBox Join(.toarray, vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", 12, 112, "aa3", "aa2", "aa6")
End With.Add it
Next.Sort .Reverse ' foutmelding
De Arrays in een Arraylist kun je niet sorteren met de methoden .Sort. of .Reverse.Daar is toch een oplossing voor: 1. zet de waarden van de kolom waarop gesorteerd moet worden in de Arraylist 2. sorteer die items met .Sort of .Reverse 3. zet de gesorteerde items in een Array met .ToArray 4. maak de ArrayList leeg 5. voeg in de volgorde van de gesorteerde items de 'rijen' van de te sorteren Array toe aan de Arraylist Sub M_snb()
sn = Sheet1.Range("A1:G20")
End SubWith CreateObject("System.Collections.Arraylist") For j = 1 To UBound(sn)
End With.Add sn(j, 3)
Next.Sort sp = .ToArray .Clear For j = 0 To UBound(sp) For jj = 1 To UBound(sn)
NextIf sn(jj, 3) = sp(j) Then
Next.Add Application.Index(sn, jj)
End Ifsn(jj, 3) = "" Exit For For j = 0 To .Count - 1 Sheet1.Cells(j + 1, 10).Resize(, UBound(sn, 2)) = .Item(j)
Next
In het argument geef je de inhoud van het element op. Als het element met de opgegeven inhoud niet bestaat negeert de methode de opdracht; VBA genereert geen foutmelding. Verwijder het eerste item met de waarde "aa3": With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.Remove "aa3" MsgBox Join(.ToArray,vbLf)
Als het opgegeven indexnummer niet bestaat genereert VBA een foutmelding. Verwijder het 5e element (met indexnummer 4) With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa5", "aa6")
End With.Add it
Next.RemoveAt 4 MsgBox Join(.ToArray,vbLf)
Als 1 van de argumenten onjuist is genereert VBA een foutmelding. Verwijder 3 elementen vanaf indexnummer 2: With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.RemoveRange 2,4 MsgBox Join(.ToArray,vbLf) With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Next.Clear MsgBox .Count
Wijzigingen in die kopie hebben geen effekt op de oorspronkelijke ArrayList. Omdat de kopie ook weer een ArrayList is, dus een object, is de instructie 'Set' noodzakelijk bij de toewijzing aan een variabele. With CreateObject("System.Collections.ArrayList")
For Each it In Array("aa1", "aa2", "aa3", "aa3", "aa2", "aa6")
End With.Add it
Nextset c_00=.Clone msgbox join(c_00.ToArray,vbLf) c_00.item(2)="~" msgbox join(.ToArray,vbLf) & vbLf & vbLf & join(c_00.ToArray,vbLf) |