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.
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).
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.
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.
Set 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
Alle methoden: .Add, .Item()=, =Item() en objectvariabele()= werken analoog zoals hierboven beschreven.
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 With
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.
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"
With CreateObject("scripting.dictionary")
For Each it In Sheets("sheet1").OLEObjects
end with.Item(it) = it.Name
Next
With CreateObject("scripting.dictionary")
For Each it In Array("bb1", 12, 45673, Date + 10, sheet4)
end with.Item(it) = "Item 1" & .Count
Next
- 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
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
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"
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)
With CreateObject("scripting.dictionary")
.Item("aa18") = Array("aa1", "aa2", "aa3")
End WithAdd "aa19", Split("bb1_cc1_dd1", "_") dict_snb("aa20") = Array("aa1", "aa2", "aa3")
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")
With CreateObject("scripting.dictionary")
For Each it In Controls
End WithSet .Item(it.Name) = it
Next.Add it.name& "_", it
With CreateObject("scripting.dictionary")
For Each it In Sheets("sheet1").OLEObjects
End WithSet .Item(it.Name) = it
Next.Add it.name & "_", it
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
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
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
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"
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")
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
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))
With 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)
Next
With 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"), ""))
' 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)
With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Nextsn = .Keys
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)
- het maximum van keys die uit getallen bestaan (Excel) MsgBox Application.Max(.Keys) MsgBox Application.Min(.Keys) MsgBox Application.Large(.Keys, 3)
Door 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))
Next
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
With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa1", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Nextsn = .Items
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)
- het maximum van keys die uit getallen bestaan (Excel) MsgBox Application.Max(.Items) MsgBox Application.Min(.Items) MsgBox Application.Large(.Items, 3)
Door 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)
With CreateObject("scripting.dictionary") .Item("aa") = "Dit is het eerste item"
End WithMsgBox .Item("aa") .Key("aa") = "bb" MsgBox .Item("bb")
With CreateObject("scripting.dictionary") .Item("aa") = "Dit is het eerste item"
End With.Item("bb") = .Item("aa") MsgBox .Item("bb")
With CreateObject("scripting.dictionary") For Each it In Array("aa1", "aa2", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Next.Remove "aa3"
With 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.
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, "|")
With 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, "|")
With 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)
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) 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)
With CreateObject("scripting.dictionary") For Each it In Array("2", "33", "aa3", "aa4", "aa2")
End With.Item(it) = it & "_inhoud"
Next.RemoveAll
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.
With New Dictionary .Add "aa1", "vandaag"
End With
Set d_snb = New Dictionary d_snb.Add "aa1", "vandaag"
(bijv. het werkboek, een werkblad, een userform of een macromodule). Private d_snb As New Dictionary d_snb.Add "aa1", "PPP"
Public d_snb As New Dictionary In het declaratiedeel: Public d_snb As dictionary Set d_snb = New Dictionary
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)
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)
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)
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
next
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
Next
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
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
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" ' - - -
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 |