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. 2. Waarvoor kun je een ArrayList gebruiken ? Je kunt de ArrayList gebruiken om gegevens uit allerlei bronnen bij elkaar te zetten en snel te bewerken omdat ze via de ArrayList in het werkgeheugen geladen zijn en snel toegankelijk zijn.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. 3. Waar komt de ArrayList vandaan ? De ArrayList maakt geen deel uit van de standaard VBA-bibliotheek.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") 4. Hoe maak je een ArrayList ? Er zijn verschillende methoden om een ArrayList aan te maken.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' 4.1 Met referentie naar de bibliotheek: 'early binding' Als je de ArrayList alleen maar nodig hebt in 1 macro of funktie kun je de definitie van de ArrayList tot die procedure beperken.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. 4.1.3.1 Gelijktijdige declaratie en toewijzing Om een variabele beschikbaar te maken in alle macro's en funkties van een codemodule moet je de variabele declareren in het declaratiegebied van de codemodule.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 4.1.3.2 Declaratie in het declaratiegebied en toewijzing in een procedure Die variabele moet je eerst in het declaratiegebied van de codemodule van een macromodule 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 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 4.2 Zonder referentie naar de bibliotheek: 'late binding' Als je de ArrayList alleen maar nodig hebt in 1 macro of funktie kun je de definitie van de ArrayList tot die procedure beperken.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. 5.1 afzonderlijke items toevoegen De methode .Add plaatst een item altijd achter het laatste element van de ArrayList.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" 5.3.3 een niet-afdrukbaar teken 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 5.3.5 een datum (typename: Date) With CreateObject("System.Collections.ArrayList")
.Add Date
End With.Add CDate("23-04-2012") .Insert 2, DateSerial(2013, 10, 12) 5.3.6 een 1-dimensionele Array (typename: Variant()) With CreateObject("System.Collections.ArrayList")
.Add Array("aa1", "aa2", "aa3")
End With.Add Split("bb1_cc1_dd1", "_") .Insert 1,Array("aa1", "aa2", "aa3") 5.3.7 een meer-dimensionele Array (typename: Variant())
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") 5.3.9 de controls in een userform With CreateObject("System.Collections.ArrayList")
For Each it In Controls
End With.Add it
Next5.3.10 de ActiveX-controls in een werkblad With CreateObject("System.Collections.ArrayList")
For Each it In Sheets("sheet1").OLEObjects
End With.Add it
Next5.3.11 alle werkbladen van een werkboek With CreateObject("System.Collections.ArrayList")
For Each sh In Sheets
End With.Add sh
Next.Insert 1, sh 6. De omvang van een ArrayList De eigenschap .Count geeft het aantal items van/in een ArrayList weer.With CreateObject("System.Collections.ArrayList")
For Each sh In Sheets
End With.Add sh
Next.Insert 1, sh msgbox .count 7. Controle of een item in een ArrayList voorkomt Een ArrayList kan een onbeperkt aantal keer dezelfde waarde bevatten.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 ). 8. Controle op welke positie een item in een ArrayList voorkomt De eigenschap .IndexOf geeft aan op welke positie een item in een ArrayList staat.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") 9. Lezen/ophalen van elementen 9.1 Lezen/ophalen van 1 element Aan de hand van het indexnummer kan de waarde van een element in de ArrayList worden gelezen.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 9.2 Lezen/ophalen van opeenvolgende elementen Met de methode.GetRange kun je aangeven vanaf welk indexnummer (1e argument) je hoeveel (2e argument) opeenvolgende elementen uit de ArrayList wil lezen.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)
9.3 Lezen/ophalen van alle elementen Met de methode .ToArray kun je alle elementen uit de ArrayList naar een 1-dimensionele Array schrijven.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) 11.1 oplopend sorteren van elementen De methode .Sort sorteert alle elementen in de ArrayList oplopend.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
11.2 aflopend sorteren van elementen De methode .Reverse sorteert alle elementen in de ArrayList aflopend.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)
Next12. verwijder elementen uit een ArrayList 12.1 verwijder 1 element op basis van de inhoud De methode .Remove verwijdert 1 element uit de ArrayList.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) 12.2 verwijder 1 element op basis van positie (index) in de ArrayList De methode .RemoveAt verwijdert het element op de positie/met de index in het argument.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) 12.3 verwijder opeenvolgende elementen De methode .RemoveRange verwijdert een groep aaneengesloten elementen. In het eerste argument geef je aan vanaf welk indexnummer elementen verwijderd moeten worden; in het tweede argument geef je aan hoeveel aaneengesloten elementen verwijderd moeten worden.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 13. maak een kopie van de ArrayList Voor een ArrayList bestaat een aparte methode om een onafhankelijke kopie te maken: .Clone.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) |