voorbeeldbestand
Dictionaries
|
1 Wat is een dictionary 2 Waarvoor een dictionary 3 Dictionary achtergrond 4 Dictionary aanroepen 5 Dictionary vullen 5.1 methode .Add 5.2 methode .Item( )= 5.3 methode =.Item() 5.4 met objectvariabele 6 Toevoegen of vervangen ? 6.1 nieuwe sleutel 6.2 bestaande sleutel 6.2.1 methode .Add 6.2.2 methode .Item()= 6.2.3 methode =.Item() 6.2.4 met objectvariabele 7 Sleutels 7.1 tekstreeks 7.2 getal 7.3 datum 7.4 object 7.5 ActiveX-controls 7.6 Diverse sleutels 8 Unieke sleutel 9 Genereer unieke sleutels 10 Unieke elementen 11 Items 11.1 leeg item 11.2 lege tekstreeks 11.3 gewone tekstreeks 11.4 niet-afdrukbaar teken 11.5 getal 11.6 datum 11.7 1-dimensionele matrix 11.8 meer-dimensionele matrix 11.9 object 11.10 userformcontrols 11.11 ActiveX-controls 11.12 alle werkbladen 11.13 User Defined Type (UDT) 12 Dictionary: omvang 13 zoek sleutel / item 14 opvragen element 14.1 unieke sleutel 14.2 indexnummer 14.3 indexnummer van sleutel 14.4 Sleutels: lus 14.5 Filter sleutels 15 Sleutelverzameling 15.1 Opslaan 15.2 in variabele 15.3 in tekstreeks 15.4 berekeningen op sleutels 15.5 Filter sleutels 16 Itemverzameling 16.1 opslaan 16.2 in variabele 16.3 in tekstreeks 16.4 berekeningen op items 16.5 filter items 17 Wijzig sleutel 18 Kopieer item 19 Verwijder item 20 Wijzig item-inhoud 20.1 Vervang inhoud 20.2 Voeg toe 20.3 bewerk / bereken 20.3.1 getal 20.3.2 datum 20.3.3 boolean 20.4 wijzig een array-item 20.4.1 1-dimensionele array 20.4.2 2-dimensionele array 21 Dictionary legen 22 Early binding en late binding 22.1 Late binding 22.1.1 impliciet object 22.1.2 object variable 22.2 early binding 22.2.1 impliciet object 22.2.2. objectvariabele 22.2.3.1 private objectvariable 22.2.3.2 public objectvariable 23 Voorbeelden 23.1 Ontdubbelen 23.2 Filter hoogste waarde 23.3 Filter laagste waarde 23.4 records aanvullen 23.5 werkbladen-integratie 23.6 csv gegevens-integratie 23.7 unieke elementenlijst 23.8 vulcontrole ActiveX controls 23.9 werkbladcontrole 23.10 tekens naar 2-dimensionele matrix |
Een dictionary in VBA is een verzamelobject: je kunt er allerlei verschillende zaken in opbergen: getallen, teksten, datums, arrays, ranges, variabelen en objecten. Ieder opgeslagen item in een dictionary krijgt een unieke sleutel. Daarmee kun je het item rechtstreeks benaderen (lezen/schrijven/bewerken). VBA heeft verschillende mogelijkheden om gegevens op te slaan: - een dictionary - een collection - een array (matrix) variabele - een ActiveX ComboBox - een ActiveX ListBox - een Userform control ComboBox - een Userform control ListBox - een sortedlist - een arraylist De keuze voor een van deze methoden is afhankelijk van het te bereiken doel. In deze tutorial wordt geen poging gedaan al deze methoden met elkaar te vergelijken. We beperken ons tot een besprekeing van de mogelijkheden van de Dictionary. Hoe beter we daarvan op de hoogte zijn, hoe gemakkeljker we kunnen besluiten deze toe te passen. Een belangrijk kenmerk van de Dictionary is het gebruik van een unieke sleutel. Een item hoeft dus niet gezocht te worden met een lus of met de Excelfunktie application.match. In dat opzicht heeft een dictionary een voordeel ten opzichte van bijv. een array/matrix-variabele. De manier waarop de dictionary items opslaat is vergelijkbaar met de methode Collection De Dictionary heeft echter een aantal eigenschappen als .keys, .items en .removeall, waardoor het werken met een dictionary handiger kan zijn dan het gebruik van een collection. De keus voor een Dictionary ten opzichte van bijv. een matrix-variabele of Collection is dus afhankelijk van wat je met opgeborgen items wil doen. 2 Waarvoor kun je een dictionary gebruiken ? Je kunt de Dictionary gebruiken om gegevens uit allerlei bronnen bij elkaar te zetten en snel te bewerken omdat ze via de dictionary 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 dictionary snel is. Globaal gezegd kun je een dictionary gebruiken om gegevens die een bepaald uniek gemeenschappelijk kenmerk hebben (de sleutel) bij elkaar te zetten. Gegevens die op diverse plaatsen zijn geregistreerd kun je zo eenvoudig integreren. Omdat een Dictionary alleen unieke sleutels kan bevatten kun je de sleuteleigenschap ook benutten om een reeks van unieke tekstreeksen, getallen, datums maken. De Dictionary is hiervoor niet ontworpen, maar het is een handige neveneigenschap. De unieke sleutels zijn niet gesorteerd; ze krijgen de volgorde waarin ze aan de Dictionary zijn toegevoegd. Wil je een gesorteerde lijst van unieke sleutels hebben dan zul je de aan te bieden gegevens eerst moeten sorteren, of een andere VBA bibliotheek moeten gebruiken (bijv. system.arraylist of system.sortedlist) Voorbeelden waarin een unieke lijst praktisch is: een validatielijst in Excel, de inhoud van een ActiveX-control (combobox of listbox) of een Userformcontrol (combobox of listbox). 3 Waar komt de Dictionary vandaan ? De Dictionary maakt geen deel uit van de standaard VBA-bibliotheek.De dictionary is onderdeel van de bibliotheek Microsoft Scripting Runtime Die bevindt zich in het bestand ..\Windows\system32\scrrun.DLL of in een vergelijkbare directory Je kunt via de VBEditor een aktieve verbinding leggen naar dit bestand door Microsoft Scripting Runtime bij de Referenties aan te vinken (Extra/referenties... of Tools/References..) Als je een bestand waarin je gebruik maatk van een dictionary verspreidt, wordt meteen ook die verbinding naar deze bibliotheek meeverspreid. 4 Hoe roep je een Dictionary aan ? Er zijn verschillende methoden om een Dictionary aan te roepen.Omdat ik het belangrijker vind eerst te bespreken wat je met een dictionary kunt doen behandel ik deze pas in het laatste deel van deze tutorial. Tot dat laatste deel gebruik ik voor de eenvoud slechts 1 methode. Dat betekent niet dat dat de beste methode zou zijn; het is wel de eenvoudigste en minst storingsgevoelige. Om een Dictionary te maken heb je aan deze code voldoende With CreateObject("scripting.dictionary") End With Alle opdrachten / eigenschappen die beginnen met een . tussen With ... End With verwijzen naar de aangemaakte Dictionary zoals bijvoorbeeld: With CreateObject("scripting.dictionary") .Add "sleutel", "inhoud"
End Withen zoals: With CreateObject("scripting.dictionary") MsgBox .Count
End WithVoor ieder item heb je 2 dingen nodig: de inhoud van het item en een unieke sleutel De inhoud van een item kan van alles zijn: getallen, teksten, datums, arrays, ranges, variabelen, collections, dictionaries,een lege tekenreeks, niets en objecten De sleutel kan een getal, tekstreeks, datum of object zijn, of een variabele met een getal, tekstreeks, datum of object Een sleutel kan geen 1- of meerdimensionele array zijn. Voor de duidelijkheid zal ik in deze tutorial alleen tekstreeksen gebruiken als sleutel; daardoor blijft duidelijk dat het om sleutels gaat en niet om indexnummers. Er zijn 4 methoden om een item aan een dictionary toe te voegen Voeg een item toe aan de Dictionary met de inhoud "inhoud" en de sleutel "sleutel" With CreateObject("scripting.dictionary") .Add "sleutel", "inhoud"
End WithDit item in de Dictionary heeft dan alle kenmerken van het object: With CreateObject("scripting.dictionary") .Add "gebied", sheet1.range("A1:K10")
End WithMsgbox .item("gebied").rows.count With CreateObject("scripting.dictionary") .Item("sleutel") = "inhoud"
End WithDit item in de Dictionary heeft dan alle kenmerken van het object: With CreateObject("scripting.dictionary") Set .Item("gebied") = sheet1.range("A1:K10")
End WithMsgbox .item("gebied").rows.count With CreateObject("scripting.dictionary") x0 = .Item("sleutel")
End WithAls het item met deze sleutel niet bestaaat voegt de code het item toe met de opgegeven sleutel Aan het item wordt dan geen inhoud toegekend. 5.4 methode met objectvariabele Als je van de dictionary een objectvariabele maaktSet dict_snb = CreateObject("scripting.dictionary") dict_snb("sleutel") = Date Dit kun je ook anders schrijven; het resultaat is identiek Set dict_snb = CreateObject("scripting.dictionary") dict_snb.Item("sleutel") = Date 6.1 de sleutel bestaat niet in de Dictionary Als een sleutel niet bestaat wordt een nieuwe sleutel aangemaakt en het item toegevoegd.Alle methoden: .Add, .Item()=, =Item() en objectvariabele()= werken analoog zoals hierboven beschreven. 6.2 de sleutel bestaat al in de Dictionary Als een sleutel al bestaat krijg je met de methode .Add een foutmelding dat de sleutel al bestaat:Dit is vergelijkbaar met het gebruik van een Collection. With CreateObject("scripting.dictionary") .Add "sleutel", Date
End With.Add "sleutel", "nieuw" In tegenstelling tot bij de methode .Add en een Collection krijg je nu geen foutmelding dat de sleutel al bestaat. With CreateObject("scripting.dictionary") .Item("sleutel") = Date
End WithMsgBox .Item("sleutel") .Item("sleutel") = "nieuw" MsgBox .Item("sleutel") Als de sleutel al bestaat verandert er niets aan/in de Dictionary. With CreateObject("scripting.dictionary") x0 = .Item("sleutel")
End With6.2.4 methode met objectvariabele Als een sleutel al bestaat wordt met deze methode de inhoud van het bestaande item vervangen door de laatste waarde.In tegenstelling tot bij de methode .Add en een Collection krijg je geen foutmelding dat de sleutel al bestaat. Set dict_snb = CreateObject("scripting.dictionary") dict_snb("sleutel") = Date MsgBox dict_snb("sleutel") dict_snb("sleutel") = "nieuw" MsgBox dict_snb("sleutel") Set dict_snb = CreateObject("scripting.dictionary") dict_snb.Item("sleutel") = Date MsgBox dict_snb.Item("sleutel") dict_snb.Item("sleutel") = "nieuw" MsgBox dict_snb.Item("sleutel") Een sleutel kan een tekstreeks, een getal, een datum of een object zijn. Een sleutel kan ook een variabele zijn die een tekstreeks, een getal, een datum, of een object bevat. Een sleutel kan geen array (1- of meerdimensioneel) zijn. Een Dictionary kan verschillende soorten sleutels (tekstreeks, getal, datum, object) bevatten. Illustratie van verschillende soorten sleutels With CreateObject("scripting.dictionary")
.Items("aa1") = "voorbeeld 1 "
end with.Add "aa2", "voorbeeld 2" x = .Item("aa3") dict_snb("aa4") = "voorbeeld 3" With CreateObject("scripting.dictionary")
.Items(2) = "voorbeeld 4"
end with.Items(1234589) = "voorbeeld 5" .Add 23, "voorbeeld 6" x = .Item(45) dict_snb(56788) = "voorbeeld 7" With CreateObject("scripting.dictionary")
.Items(Date) = "voorbeeld 8"
end with.Items(CDate("12-03-2013")) = "voorbeeld 9" .Add DateAdd("m", 2, 1), " voorbeeld 10" x = .Item(DateSerial(2013, 5, 5)) dict_snb(56788) = " voorbeeld 11" With CreateObject("scripting.dictionary")
.Items(TextBox1) = "voorbeeld 12"
end with.Items(TextBox2) = "voorbeeld 13" .Add ListBox1, "voorbeeld 14" x = .Item(Sheet1) dict_snb(ComboBox1) = "voorbeeld 15" 7.5 ActiveX-controls in een werkblad With CreateObject("scripting.dictionary")
For Each it In Sheets("sheet1").OLEObjects
end with.Item(it) = it.Name
Next7.6 Verschillende soorten sleutels in 1 Dictionary With CreateObject("scripting.dictionary")
For Each it In Array("bb1", 12, 45673, Date + 10, sheet4)
end with.Item(it) = "Item 1" & .Count
Next8 Wanneer is een sleutel uniek ? Er zijn twee mogelijkheden:- onderscheid tussen hoofd- en kleine letters; VanDaaG is een andere sleutel dan Vandaag - geen onderscheid tussen hoofd- en kleine letters; VanDaaG is dezelfde sleutel als vandaag De manier waarop sleutels met elkaar worden vergeleken stel je in met de eigenschap .comparemode - geen specificatie van de comparemode: onderscheid tussen hoofd- en kleine letters - .comparemode = BinaryCompare (0) : onderscheid tussen hoofd- en kleine letters - .comparemode = TextCompare (1) : geen onderscheid tussen hoofd- en kleine letters
'8 unieke sleutels, want onderscheid tussen onderkast en bovenkast
With CreateObject("scripting.dictionary") For Each it In Array("aa1", "AA1", "Aa1", "aA1", "bb1", "BB1", "Bb1", "bB1")
End Withy = .Item(it)
NextMsgBox .Count MsgBox Join(.Keys, vbLf)
'8 unieke sleutels, want onderscheid tussen onderkast en bovenkast
With CreateObject("scripting.dictionary") .CompareMode = 0
End WithFor Each it In Array("aa1", "AA1", "Aa1", "aA1", "bb1", "BB1", "Bb1", "bB1") y = .Item(it)
NextMsgBox .Count MsgBox Join(.Keys, vbLf)
'2 unieke sleutels, want onderscheid tussen onderkast en bovenkast
With CreateObject("scripting.dictionary") .CompareMode = 1 For Each it In Array("aa1", "AA1", "Aa1", "aA1", "bb1", "BB1", "Bb1", "bB1") y = .Item(it)
NextMsgBox .Count MsgBox Join(.Keys, vbLf) End With 9 Genereer automatisch unieke sleutels Soms moeten alle items in een dictionary opgenomen worden.Of gegevends aan eenzelfde sleutel moeten worden toegekend maakt dan niet uit. Dan is het van belang voor ieder item een unieke sleutel te genereren, om zo ieder item aan de dictionary toe te voegen. Dat kun je bijv. doen door gebruik te maken van de eigenschap .count van de dictionary With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(.Count) = it & "_inhoud"
Next- om een tekstreeks om te zetten naar een 2-dimensionele matrix: Voorbeeld II - om een aantal ActiveX controls te groeperen: Voorbeeld III 10 Een lijst van unieke elementen Door items toe te voegen aan een dictionary creëer je een lijst van unieke sleutels.Daarmee kun je dus een lijst met unieke elementen maken; een sleutel is nl. per definitie uniek. Om die lijst te maken is het niet nodig gegevens aan het item toe te kennen. De methode om dit te doen is het uitlezen van een item. Als het item niet bestaat, wordt een sleutel toegevoegd; als de sleutel bestaat gebeurt er niets. De methode geeft geen foutmeldingen die eventueel afgevangen zouden moeten worden
' vanwege de dubbele sleutels 22 en 44 bevat de dictionary 5 unieke sleutels
With CreateObject("scripting.dictionary") For Each it In Array(22, 33, 44, 22, 3, 22, 55, 44)
End Withy = .Item(it)
NextMsgBox .Count MsgBox Join(.Keys, vbLf) 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. Voor de sleutel gebruiken we alleen een tekenreeks. With CreateObject("scripting.dictionary")
x0 = .Item("aa1")
End WithWith CreateObject("scripting.dictionary")
.Item("aa2") = vbNullString
End With.Item("aa3") = "" .Add "aa4", "" dict_snb("aa5") = vbNullString With CreateObject("scripting.dictionary")
.Item("aa6") = "abcde"
End With.Add "aa7", "abcde" dict_snb("aa8") = "abcde" 11.4 een niet-afdrukbaar teken With CreateObject("scripting.dictionary")
.Item("aa9") = vbTab
End WithAdd "aa10", vbLf dict_snb("aa11") = vbCrLf
' typename: Integer
' typename: Long With CreateObject("scripting.dictionary")
.Item("aa12") = 12345
End With.Add "aa13" = 1234589 dict_snb("aa14") = RGB(23, 45, 678) With CreateObject("scripting.dictionary")
.Item("aa15") = Date
End With.Add "aa16", CDate("23-04-2012") dict_snb("aa17") = DateSerial(2013, 10, 12) 11.7 een 1-dimensionele matrix (array) (typename: Variant())With CreateObject("scripting.dictionary")
.Item("aa18") = Array("aa1", "aa2", "aa3")
End WithAdd "aa19", Split("bb1_cc1_dd1", "_") dict_snb("aa20") = Array("aa1", "aa2", "aa3") 11.8 een meer-dimensionele matrix (typename: Variant())With CreateObject("scripting.dictionary")
ReDim sn(6, 10)
End With.Item("aa21") = sn .Add "aa22", Range("A1:K10") dict_snb("aa23") = Range("A1:K10").Formula
' typename: Range
With CreateObject("scripting.dictionary")
Set .Items("aa24") = Range("A1:K10")
End WithSet dict_snb("aa25") = Range("A1:K10") .Add "aa26", Range("A1:K10") 11.10 de controls in een userform With CreateObject("scripting.dictionary")
For Each it In Controls
End WithSet .Item(it.Name) = it
Next.Add it.name& "_", it 11.11 de ActiveX-controls in een werkblad With CreateObject("scripting.dictionary")
For Each it In Sheets("sheet1").OLEObjects
End WithSet .Item(it.Name) = it
Next.Add it.name & "_", it 11.12 alle werkbladen van een werkboek With CreateObject("scripting.dictionary")
For Each sh In Sheets
End WithSet .Item(sh.Name) = sh
Next.Add sh.Name & "_", sh Set dict_snb(sh.Name & "_#") = sh 11.13 een User Defined Type (UDT)k Een User Defined Type (UDT) kun je in een array zetten.bijvoorbeeld Public Type translation dutch As String
End Typegerman As String french As String italian As String Sub filling_type_array() ReDim sn(2) As translation
end subFor j = 0 To 2 sn(j).dutch = Choose(j + 1, "tafel", "wijn", "water")
Nextsn(j).german = Choose(j + 1, "Tisch", "Wein", "Wasser") sn(j).french = Choose(j + 1, "table", "vin", "eau") sn(j).italian = Choose(j + 1, "tavola", "vino", "aqua") MsgBox sn(2).german & " = " & sn(2).italian For j=0 to ubound(sn) MsgBox sn(j).german & " = " & sn(j).italian
nextEen UDT kun je niet in een dictionary (noch een collection) zetten. De opdracht Dim woord As translation With CreateObject("scripting.dictionary") .Add "overzicht", woord
End WithMet een andere methode kun je wel een soortgelijk effekt bereiken: - maak een klassemodule (bijv. met de naam 'trans') - declareer daarin de eigenschappen van de klasse: Public german As String, french As String, italian As String
Ter illustratie 3 methoden om dat te doen: NB. de Nederlandse woorden worden als sleutel (key) in de Dictionary gebruikt. Sub type_class_in_dictionary()
With CreateObject("scripting.dictionary")
End SubSet sn = New trans
End Withsn.german = "Tisch" sn.french = "table" sn.italian = "tavola" .Add "tafel", sn Set .Item("wijn") = New trans .Item("wijn").german = "Wein" .Item("wijn").french = "vin" .Item("wijn").italian = "vino" .Add "water", New trans .Item("water").german = "Wasser" .Item("water").french = "eau" .Item("water").italian = "aqua" MsgBox .Item("tafel").french MsgBox .Item("wijn").italian 12 Het aantal elementen in een Dictionary De methode Dictionary houdt zelf bij hoeveel elementen een Dictionary bevat.De eigenschap .Count geeft het aantal items van een Dictionary weer. Omdat ieder item een eigen unieke sleutel heeft geeft de eigenschap .Count ook meteen het aantal unieke sleutels weer in de Dictionary. De funktie .Items bevat alle items van de Dictionary, weergegeven in een 1-dimensionele array. De eigenschap Ubound() van een array geeft het aantal elementen van de array weer. Omdat een 1-dimensionele array standaard de ondergrens 0 heeft, geeft ook Ubound(.items)+1 het aantal elementen in een Dictionary weer. De funktie .Keys bevat alle sleutels van de Dictionary, weergegeven in een 1-dimensionele array. De eigenschap Ubound() van een array geeft het aantal elementen van de array weer. Omdat een 1-dimensionele array standaard de ondergrens 0 heeft, geeft ook Ubound(.keys)+1 het aantal elementen in een Dictionary weer. Equivalente methodes om de omvang van een Dictionary te bepalen zijn dus With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa2")
End Withy = .Item(it)
NextMsgBox .Count MsgBox UBound(.Keys) + 1 MsgBox UBound(.Items) + 1 13 Controle of een sleutel / item in de Dictionary voorkomt Als je een item aan de Dictionary wil toevoegen met de methode .Add krijg je een foutmelding als de sleutel voor dat item al bestaat.Je kunt die foutmelding voorkomen door eerst te controleren of de sleutel al in de Dictionary aanwezig is With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End WithIf Not .Exists(it) Then .Add it, it & "_inhoud"
NextAls dat niet de bedoeling is kun je controleren of de sleutel al in de Dictionary aanwezig is. With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End WithIf Not .Exists(it) Then .Item(it) = it & "_inhoud"
NextAls de sleutel nl. nog niet bestaat wordt die automatisch aangemaakt als je de item-inhoud probeert uit te lezen met de code. y = .Item("sleutel") With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
NextIf .Exists("aa2") Then .Item("aa2") = "nieuwe waarde" 14 Hoe vraag je 1 element uit een Dictionary op ? De Dictionary is ervoor ontworpen om met de sleutel direkt een item te kunnen benaderen (lezen/schrijven)Met .item("aa2") krijg je de inhoud van het item met de sleutel "aa2" With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
NextMsgBox .Item("aa2") 14.2 Met het indexnummer van het item De funktie .Items is een 1-dimensionele array.De volgorde waarin elementen aan de Dictionary worden toegevoegd bepaalt het indexnummer van de array .items. Het eerste element krijgt indexnummer 1, het laatste indexnummer komt overeen met de eigenschap .count. Je zou verwachten dat .items(2) het tweede element van de Dictionary zou opleveren. Deze schrijfwijze werkt echter niet. In plaats daarvan moet je schrijfwijze .items()(2) gebruiken.
' het eerste item
' het tweede item ' het laatste item With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2") .Item(it) = it & "_inhoud"
NextMsgBox .Items()(1) MsgBox .Items()(2) MsgBox .Items()(.count) End With 14.3 Met het indexnummer van een sleutel De funktie .Keys is een 1-dimensionele array.De volgorde waarin elementen aan de Dictionary worden toegevoegd bepaalt het indexnummer van de array .keys. Het eerste element krijgt indexnummer 1, het laatste indexnummer komt overeen met de eigenschap .count. Je zou verwachten dat .keys(2) de tweede sleutel van de Dictionary zou opleveren. Deze schrijfwijze werkt echter niet. In plaats daarvan moet je schrijfwijze .keys()(2) gebruiken.
' de eerste sleutel
' de tweede sleutel ' de laatste sleutel With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
NextMsgBox .item(.keys()(1)) MsgBox .item(.keys()(2)) MsgBox .item(.keys()(.count)) 14.4 Loop alle sleutels in de Dictionary af en toets op een voorwaarde Hiervoor maken we gebruik van de function .Keys waarin alle sleutels staan in de vorm van een 1-dimensionele matrixWith CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
NextFor Each it In .Keys If it = "aa4" Then MsgBox .Item(it)
Next14.5 Filter de sleutels in de Dictionary Hiervoor maken we gebruik van de function .Keys waarin alle sleutels staan in de vorm van een 1-dimensionele matrixWith CreateObject("scripting.dictionary") For Each it In Array("aa14", "bb345", "cc392", "rrr987")
End With.Item(it) = it & "_inhoud" Next MsgBox .Item(Join(Filter(.Keys, "cc"), "")) 15 Hoe kun je de verzameling van sleutels gebruiken ? 15.1 Schrijf alle sleutels naar een werkblad
' in een rij
' in een kolom With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
NextCells(1, 1).Resize(, .Count) = .Keys Cells(1, 1).Resize(.Count) = Application.Transpose(.Keys) 15.2 Zet alle sleutels in een variabele De variabele wordt automatisch een array-variabele met ondergrens 0With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Nextsn = .Keys 15.3 Zet alle sleutels in een tekstreeks With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", 22, 3, 22, DateSerial(2013, 12, 3), 44)
End With.Item(it) = it & "_inhoud"
NextMsgBox Join(.Keys, vbLf) 15.4 Voer berekeningen uit op de sleutels Veel Excel werkbladfunkties kunnen worden toegepast op de array .keys als de keys uit getallen bestaan.- het maximum van keys die uit getallen bestaan (Excel) MsgBox Application.Max(.Keys) MsgBox Application.Min(.Keys) MsgBox Application.Large(.Keys, 3) 15.5 Filter de sleutels op een bepaald kenmerk Bijv. filter op het jaar 2012Door het gebruik van de methode Filter worden alle sleutels in de functie .keys geconverteerd naar tekst. De filterterm dient dan ook een tekstreeks te zijn. With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", DateSerial(2012, 12, 3), DateSerial(2012, 12, 4), DateSerial(2012, 12, 8), 22, DateSerial(2013, 12, 3), 44)
End With.Item(it) = it & "_inhoud"
NextMsgBox Join(Filter(.Keys, "-2012"), vbLf) Als je de gefilterde sleutels wil gebruiken om de overeenkomstige items op te roepen zul je ze naar de oorspronkelijke vorm, in dit geval datums moet terugconverteren With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", DateSerial(2012, 12, 3), DateSerial(2012, 12, 4), DateSerial(2012, 12, 8), 22, DateSerial(2013, 12, 3), 44)
End With.Item(it) = it & "inhoud"
NextFor Each it In Filter(.Keys, "-2012") MsgBox .Item(CDate(it))
Next16 Hoe kun je de verzameling van items gebruiken ? 16.1 Schrijf alle items naar een werkblad NB. Dit kan alleen als ieder item naar een cel geschreven kan worden (een tekstreeks een getal, een datum)With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
NextCells(1, 1).Resize(, .Count) = .Items in een rij Cells(1, 1).Resize(.Count) = Application.Transpose(.Items) in een kolom 16.2 Zet alle items in een variabele De variabele wordt automatisch een array-variabele met ondergrens 0With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Nextsn = .Items 16.3 Zet alle items in een tekstreeks With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", 22, 3, 22, DateSerial(2013, 12, 3), 44)
End With.Item(it) = it & "_inhoud"
NextMsgBox Join(.Items, vbLf) 16.4 Voer berekeningen uit op de items Veel Excel werkbladfunkties kunnen worden toegepast op de array .items als de items uit getallen bestaan.- het maximum van keys die uit getallen bestaan (Excel) MsgBox Application.Max(.Items) MsgBox Application.Min(.Items) MsgBox Application.Large(.Items, 3) 16.5 Filter de items op een bepaald kenmerk Bijv. filter op het jaar 2012Door het gebruik van de methode Filter worden alle items in de functie .items geconverteerd naar tekst. De filterterm dient dan ook een tekstreeks te zijn. With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", DateSerial(2012, 12, 3), DateSerial(2012, 12, 4), DateSerial(2012, 12, 8), 22, DateSerial(2013, 12, 3), 44)
End With.Item(it) = it & "_inhoud"
NextMsgBox Join(Filter(.Items, "-2012"), vbLf) 17 Wijzig de sleutel van een item Je kunt dit ook beschrijven als het 'verplaatsen' van een item binnen een Dictionary.With CreateObject("scripting.dictionary") .Item("aa") = "Dit is het eerste item"
End WithMsgBox .Item("aa") .Key("aa") = "bb" MsgBox .Item("bb") 18 Kopieer een item binnen de Dictionary Je kunt de inhoud van een bestaand item aan een andere/nieuwe sleutel koppelen.With CreateObject("scripting.dictionary") .Item("aa") = "Dit is het eerste item"
End With.Item("bb") = .Item("aa") MsgBox .Item("bb") 19 Verwijder een item uit de Dictionary With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Next.Remove "aa3" 20 Wijzig de inhoud van een item in de Dictionary 20.1 Vervang de inhoud van een item in de Dictionary Met de methode .Item wordt een bestaand item vervangen door een later toegevoegd item met dezelfde sleutelWith CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa5", "aa6")
End With.Item(it) = it & "_inhoud"
NextFor Each it In Array("aa1", "aa2", "aa5", "aa6") .Item(it) = it & "_nieuwe inhoud"
NextMsgBox Join(.Items, "|") Doordat ieder item wordt overschreven, blijven de laatste ingelezen waarden per sleutel over. Voorwaarde is een sorteerbare sleutel. Voor een voorbeeld zie voorbeeld V. 20.2 Voeg gegevens toe aan items binnen de Dictionary Deze methode werkt alleen als het item geen array is.With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = "aa"
NextFor Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2") .Item(it) = .Item(it) & "_bb"
NextMsgBox Join(.Items, "|") 20.3 Voer een bewerking / berekening uit Als het item geen array is, maar een getal, datum of boolean bevatWith CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = 10
NextFor Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2") .Item(it) = .Item(it) + 40
NextMsgBox Join(.Items, "|") With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa4")
End With.Item(it) = Date + .Count
NextFor Each it In Array("aa1", "aa2", "aa3", "aa4") .Item(it) = DateAdd("m", 1, .Item(it))
NextMsgBox Join(.Items, vbLf) With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa2")
End With.Item(it) = False
NextFor Each it In Array("aa1", "aa2", "aa3", "aa4", "aa2") .Item(it) = Format(.Item(it), "Yes/No")
NextMsgBox Join(.Items, "|") 20.4 Breng een wijziging aan in een item dat een array bevat 20.4.1 een 1-dimensionele array Het is mogelijk een element in een array van een Dictionary Item te lezenWith CreateObject("scripting.dictionary") .Item("aa") = Array("zz1", "zz2", "zz3", "zz4")
End WithMsgBox .Item("aa")(3) Hoewel deze code geen foutmelding geeft, wordt het 4e element van de array niet gewijzigd. With CreateObject("scripting.dictionary") .Item("aa") = Array("zz1", "zz2", "zz3", "zz4")
End WithMsgBox .Item("aa")(3) .Item("aa")(3) = "het vierde item is " & .Item("aa")(3) MsgBox .Item("aa")(3) - zet de array in een variabele - wijzig een of meer element(en) van de array-variabele - vervang de inhoud van het dictionary item door de array-variabele With CreateObject("scripting.dictionary") .Item("aa") = Array("zz1", "zz2", "zz3", "zz4")
End Withsn = .Item("aa") sn(3) = "het vierde item is " & sn(3) .Item("aa") = sn MsgBox .Item("aa")(3) 20.4.2 een 2-dimensionele array Het is mogelijk een element in een 2-dimensionele array van een Dictionary Item te lezenWith CreateObject("scripting.dictionary") ReDim sn(3, 4)
End WithFor j = 0 To UBound(sn) For jj = 0 To UBound(sn, 2)
Nextsn(j, jj) = j + 5 * jj
Next.Item("aa") = sn MsgBox .Item("aa")(2, 3) With CreateObject("scripting.dictionary") ReDim sn(3, 4)
End WithFor j = 0 To UBound(sn) For jj = 0 To UBound(sn, 2)
Nextsn(j, jj) = j + 5 * jj
Next.Item("aa") = sn MsgBox .Item("aa")(2, 3) .Item("aa")(2, 3) = 10 * .Item("aa")(2, 3) MsgBox .Item("aa")(2, 3) - zet de array in een variabele - wijzig een element van deze array-variabele - vervang de inhoud van het dictionary item door deze array-variabele With CreateObject("scripting.dictionary") ReDim sn(3, 4)
End WithFor j = 0 To UBound(sn) For jj = 0 To UBound(sn, 2)
Nextsn(j, jj) = j + 5 * jj
Next.Item("aa") = sn MsgBox .Item("aa")(2, 3) sp = .Item("aa") sp(2, 3) = 10 * sp(2, 3) .Item("aa") = sp MsgBox .Item("aa")(2, 3) 21 Verwijder alle items uit de Dictionary With CreateObject("scripting.dictionary") For Each it In Array("2", "33", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Next.RemoveAll 22 Early binding en late binding Zoals bij III beschreven maakt de Dictionary geen deel uit van de standaard VBA bibliotheek.De dictionary zit in de Microsoft scripting runtime bibliotheek. Dat betekent dat je die bibliotheek moet aanroepen om de code daarin te kunnen gebruiken. Je legt daarmee een koppeling naar die bibliotheek. Dat heet in automatiseringstermen 'binding' Je hebt de keuze om - eerst de koppeling naar de bibliotheek te leggen en daarna de code ervan te gebruiken: early binding - of de koppeling pas te maken als je voor de eerste keer die code nodig hebt: late binding Tot nog toe hebben we gebruik gemaakt van de late binding methode. Die bestaat eruit dat je met de instructie CreateObject een nieuw object (instantie) aanmaakt op basis van een bepaalde bibliotheek. Welke tekst je moet gebruiken na CreateObject voor de verschilleden VBA bibliotheken is niet erg overzichtelijk. Bij een Dictionary is het in ieder geval: Createobject("scripting.dictionary") - legt een koppeling naar de bibliotheek Microsoft Scripting Runtime - maakt een nieuw object (instantie) op basis van deze bibliotheek Beide methoden (early en late binding) zijn uitwisselbaar. Doorslaggevend is je eigen voorkeur. Om met het object te kunnen werken (de eigenschappen en methoden) moet je van die nieuwe instantie een object maken. Dat kan impliciet met de methode With.... End With With CreateObject("scripting.dictionary") .Add "aa1", "vandaag"
End WithSet d_snb_ = CreateObject("scripting.dictionary") d_snb.Add "aa1", "vandaag" Je kunt de koppeling met de hand leggen via de VBEditor (Alt-F11): - VBEditor/tools/references (extra/referenties/) : 'Microsoft Scripting runtime' aanvinken Je kunt de koppeling ook met een macro leggen: Sub M_link_ref_scripting() ThisWorkbook.VBProject.References.AddFromFile "C:\windows\system32\scrrun.dll"
End SubAls je het werkboek distribueert legt het bestand automatisch de link naar deze biblotheek op iedere andere computer met Office. Om met de bibliotheek te kunnen werken moeten we een nieuw object (instantie) maken, gebaseerd op deze bibliotheek. 22.2.1 early binding met impliciet object je kunt een impliciet object aanmaken met With ... End WithWith New Dictionary .Add "aa1", "vandaag"
End With22.2.2. early binding met objectvariabele Om een object aan een variabele toe te kennen is de instructie 'Set' noodzakelijkSet d_snb = New Dictionary d_snb.Add "aa1", "vandaag" 22.2.3.1 early binding met gedeclareerde objectvariable: 'private' Je kunt de objectvariabele ook al meteen aan een nieuwe instantie toewijzen in het declaratiedeel van een codemodule.(bijv. het werkboek, een werkblad, een userform of een macromodule). Private d_snb As New Dictionary d_snb.Add "aa1", "PPP" 22.2.3.2 early binding met gedeclareerde objectvariable: 'public' Als je wil dat de objectvariabele in het hele project (werkboek) toegankelijk is, zet dan de declaratie in een macromodulePublic d_snb As New Dictionary In het declaratiedeel: Public d_snb As dictionary Set d_snb = New Dictionary 23.1 Verwijder dubbele records Kolom A bevat de sleutels voor de records.Kolommen B:.. etc, bevatten de gegevens van de records. Sub M_verwijder_dubbele_records() sn = Sheets("Sheet1").Cells(1).CurrentRegion
End SubWith CreateObject("scripting.dictionary") For j = 1 To UBound(sn)
End With.Item(sn(j, 1)) = Application.Index(sn, j, 0)
NextSheets("Sheet1").Cells(1, 4).Resize(.Count, UBound(sn, 2)) = Application.Index(.items, 0, 0) 23.2 Filter records op hoogste waarde Kolom A bevat de sleutels van de records. Kolom A bevat diverse records met dezelfde sleutel.Kolommen B: ..... bevatten de gegevens van de records. Kolom B bevat de gegevens waarop gesorteerd moet worden. Sub M_filter_records_hoogste_gegeven_in_kolomB() Sheets("Sheet1").Cells(1).CurrentRegion.Sort Sheets("Sheet1").Cells(1, 2)
End Subsn = Sheets("Sheet1").Cells(1).CurrentRegion With CreateObject("scripting.dictionary") For j = 1 To UBound(sn)
End With.Item(sn(j, 1)) = Application.Index(sn, j, 0)
NextSheets("Sheet1").Cells(1, 4).Resize(.Count, UBound(sn, 2)) = Application.Index(.items, 0, 0) 23.3 Filter records op laagste waarde Kolom A bevat de sleutels van de records. Kolom A bevat diverse records met dezelfde sleutel.Kolommen B: ..... bevatten de gegevens van de records. Kolom B bevat de gegevens waarop gesorteerd moet worden. Sub M_filter_records_laagste_gegeven_in_kolomB() Sheets("Sheet1").Cells(1).CurrentRegion.Sort Sheets("Sheet1").Cells(1, 2),2
End Subsn = Sheets("Sheet1").Cells(1).CurrentRegion With CreateObject("scripting.dictionary") For j = 1 To UBound(sn)
End With.Item(sn(j, 1)) = Application.Index(sn, j, 0)
NextSheets("Sheet1").Cells(1, 4).Resize(.Count, UBound(sn, 2)) = Application.Index(.items, 0, 0) Kolom B bevat gegevens van de records. Kolom E bevat sleutels van dezelfde records als kolom A. Kolom F bevat gegevens die aan de records van kolom A moeten worden toegevoegd. Sub M_records_aanvullen() sn = Sheets("Sheet1").Cells(1).CurrentRegion.Resize(, 3)
End Subsp = Sheets("sheet1").Cells(1, 5).CurrentRegion With CreateObject("scripting.dictionary") For j = 1 To UBound(sn)
End With.Item(sn(j, 1)) = Application.Index(sn, j, 0)
NextFor j = 1 To UBound(sp) st = .Item(sp(j, 1))
Nextst(3) = sp(j, 2) .Item(sn(j, 1)) = Application.Index(st, 0, 0) Sheets("Sheet1").Cells(1, 10).Resize(.Count, UBound(sn, 2)) = Application.Index(.items, 0, 0) 23.5 integratie van alle werkbladen in een totaalblad Sub M_integratie()
With createobject("scripting.dictionary")
End SubFor each sh in Sheets
end with.item(sh.name)=sh.usedrange
Nextsheets.add.name="totaal" for each it in .items sheets("totaal").cells(rows.count,1).end(xlup).offset(1).resize(ubound(it),ubound(it,2))=it
next23.6 Integratie van gegevens in csv bestanden in een bepaalde directory In dit voorbeeld wordt gekeken naar directory G:\OF\; pas dit aan.Sub M_integratie_csv() sn = Split(CreateObject("wscript.shell").exec("cmd /c Dir ""G:\OF\*.csv"" /b").stdout.readall, vbCrLf)
End SubWith CreateObject("scripting.dictionary") For j = 0 To UBound(sn)
End With.Item(sn(j)) = GetObject("G:\OF\" & sn(j)).Sheets(1).UsedRange.Value
NextGetObject("G:\OF\" & sn(j)).Close False Sheets.Add.Name = "totaal" For Each it In .items Sheets("totaal").Cells(Rows.Count, 1).End(xlUp).Offset(1).Resize(UBound(it), UBound(it, 2)) = it
Next23.7 maak een lijst met unieke elementen Door items toe te voegen aan een dictionary creëer je een lijst van unieke sleutels.Daarmee kun je dus een lijst met unieke elementen maken; een sleutel is nl. per definitie uniek. Om die lijst te maken is het niet nodig gegevens aan het item toe te kennen De methode om dit te doen is het uitlezen van een item. Als het item niet bestaat, wordt een sleutel toegevoegd; als de sleutel bestaat gebeurt er niets. De methode geeft geen foutmeldingen die eventueel afgevangen zouden moeten worden De lijst met unieke elementen kun je gebruiken als een validatiereeks, je kunt er een combobox of listbox mee vullen With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa2", "aa2", "aa4", "aa5")
End Withy = .Item(it)
NextSheets("sheet1").Cells(1, 10).Validation.Add 3, , , Join(.Keys, ",") Sheets("sheet1").OLEObjects("Combobox1").Object.List = .Keys Sheets("sheet1").ListBox1.List = .Keys Private Sub Userform_initialize() With CreateObject("scripting.dictionary")
End SubFor Each it In Array("aa1", "aa2", "aa3", "aa2", "aa2", "aa4", "aa5")
End Withy = .Item(it)
NextComboBox1.List = .Keys ListBox1.List = .Keys Me("ComboBox2").List = .Keys Me("ListBox2").List = .Keys Controls("ComboBox3").List = .Keys Controls("Listbox3").List = .Keys 23.8 controle of alle ActiveX elementen gevuld zijn Toon de ActiveX opdrachtknop als alle ActiveX controls een waarde hebben (niet-leeg zijn).Private dict As Dictionary Sub M_vul() Set dict = CreateObject("scripting.dictionary")
End SubFor Each it In Array("TextBox1", "TextBox2", "textbox3", "combobox4", "combobox5") Set dict(it) = Sheets("sheet1").OLEObjects(it)
NextPrivate Sub Textbox1_change() M_controle
End SubPrivate Sub M_controle() y = True
End SubFor Each it In dict.Items y = y * (it.Object.Value<>"")
NextSheets("sheet1").CommandButton1.Visible = y 23.9 check of een werkblad bestaat Zet in een macromodule:Public dict_sheets As Dictionary Sub M_sheet_exists() Set dict_sheets = CreateObject("scripting.dictionary")
End SubFor Each it In Sheets x0 = dict_sheets(it.name)
NextSub M_vervolg()
' - - -
End SubIf Not dict_sheets.Exists("Sheet10") Then Sheets.Add.Name = "Sheet10" ' - - - 23.10 maak van een tekenreeks een 2-dimensionele matrix With CreateObject("scripting.dictionary") For Each it In Split("aa1_aa2_aa3_aa4_aa5|bb1_bb2_bb3_bb4_bb5|cc1_cc2_cc3_cc4_cc5", "|") .Item(.Count) = Application.Index(Split(it, "_"), 1, 0)
NextCells(10, 1).Resize(.Count, UBound(.Item(1))) = Application.Index(.Items, 0, 0) End With |