ArrayList představuje třídu .NET Frameworku (System.Collections.Arraylist, knihovna mscorlib). Dokáže to, co musíme jinak horko těžko při práci s prostým polem ve VBA programovat – třídění, přidávání a odebírání položek, test existence položky, spojování polí aj. Vtip je v tom, že s jistými omezeními je třída ArrayList dostupná i pod VBA. Musím přiznat, že na tuto skutečnost jsem narazil poprvé cca před rokem a půl. Žádná další teorie nás nečeká, pojďme si zkusit pár příkladů. Pozn. Doporučuji kód nekrokovat, ale spouštět až do místa vložené záložky. I tak budete muset leckdy pro zobrazení skutečného obsahu proměnné v okně Locals ji sbalit a znovu rozbalit.
ArrayList v příkladech
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | Sub ProceduraArrayList() Dim objArray Dim objArrayList1 Dim objArrayList2 Dim objArrayList3 Dim objArrayList4 Dim objArrayList5 Set objArrayList1 = CreateObject("System.Collections.ArrayList") Set objArrayList2 = CreateObject("System.Collections.ArrayList") Set objArrayList3 = CreateObject("System.Collections.ArrayList") Set objArrayList4 = CreateObject("System.Collections.ArrayList") Set objArrayList5 = CreateObject("System.Collections.ArrayList") Dim intIndex As Integer Dim intPocetPolozek As Integer Dim blnPolozkaExistuje As Boolean 'plnění pole 1 With objArrayList1 .Add ("žirafa") .Add ("čížek") .Add ("motýl") End With 'plnění pole 2 With objArrayList2 .Add ("pěnkava") .Add ("chobotnice") End With 'plnění pole 3 With objArrayList3 .Add ("výr") .Add ("mravenec") End With 'přidání jednoho pole na konec druhého 'závorky nutné objArrayList1.AddRange (objArrayList2) 'vložení jednoho pole do druhého na pozici 'indexy 0, 1, ... 'závorky nutné objArrayList1.InsertRange 1, (objArrayList3) 'přepsání položek jednoho pole druhým 'indexy 0, 1, ... 'závorky nutné objArrayList1.SetRange 1, (objArrayList2) 'odstranění části pole (2 položky od indexu 1) objArrayList1.RemoveRange 1, 2 'přidání položky za n-tou položku '0 ... počátek objArrayList1.Insert 1, "tučňák" 'test existence položky blnPolozkaExistuje = objArrayList1.Contains("tučňák") 'index hledané položky s definováním 'počátku vyhledávání 'indexy 0, 1, ... intIndex = objArrayList1.IndexOf("tučňák", 0) 'odstranění položky dle jména objArrayList1.Remove ("tučňák") 'odstranění položky dle indexu 'indexy položek 0, 1, ... 'objArrayList1.RemoveAt 1 'vzestupné setřídění položek objArrayList1.Sort 'výpis položek do okna Immediate Debug.Print Join(objArrayList1.ToArray(), vbLf) 'počet položek intPocetPolozek = objArrayList1.Count 'přizpůsobení velikosti naplněným položkám 'objArrayList1.TrimToSize 'revers pole objArrayList3.Reverse 'kopie ArrayList do obyčejného pole objArray = objArrayList3.ToArray() 'převzetí části pole 'indexy 0, 1, ... Set objArrayList4 = objArrayList1.GetRange(1, 2) 'klonování pole Set objArrayList5 = objArrayList3.Clone 'vyčištění pole objArrayList1.Clear 'odstranění proměnných z paměti Set objArrayList1 = Nothing Set objArrayList2 = Nothing Set objArrayList3 = Nothing Set objArrayList4 = Nothing Set objArrayList5 = Nothing End Sub |
Největší problémy mi dělaly metody SetRange a InsertRange. Podotýkám, že práce s objektovými proměnnými pod VBA vyžaduje příkaz Set, navíc VBA prapodivně pracuje se závorkami u volání.
Pokud se pamatuji, prvně jsem ArrayList využil při třídění položek. Metoda Sort vrací korektnější výsledky, než třeba vlastní procedura (technika řazení) QuickSort. Na ukázku:
čížek
chobotnice
motýl
pěnkava
žirafa
Reference
Na knihovnu mscorlib.dll je možné se napojit i přes reference a pak není potřeba metody CreateObject. Doporučuji do knihovny nahlédnout přes Object Browser (F2).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Sub KnihovnaMSCORLIB() 'Tools / References / mscorlib.dll Dim objArrayList As New ArrayList 'plnění pole 1 With objArrayList .Add ("žirafa") .Add ("čížek") .Add ("motýl") End With End Sub |
Co se mi bohužel nepodařilo zrealizovat, je vytvoření pole s opakováním položek, např.
Set objArrayList = ArrayList.Repeat(„abc“, 7)
Je velká škoda, že ArrayList se neumí přímo zbavit duplicit. Museli bychom si zkombinovat metodu Contains třeba s GetRange nebo použít jiné objekty (HashSet). Ve VBA už kdysi pro tyto účely navrhl John Walkenbach datový typ vypůjčený z VBScriptu, a to Dictionary (neumožňuje přidání již existující položky v metodě Add). Je-li potřeba v polích pracovat s klíčem a hodnotou, nezapomínejte ani na přímo ve VBA dostupný objekt Collection.
Zásobník a fronta
V knihovně se lze odvolávat na některé další třídy (System.Collections.Hashtable, System.Collections.SortedList). My se podíváme na zásobník (zbraně), neboli stack a frontu (na poště), čili queue, známé to typy z algoritmů.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | Sub ProceduraStack() Dim objStack 'zásobník, také jinak LIFO 'tj. Last In First Out (poslední dovnitř, první ven) Set objStack = CreateObject("System.Collections.Stack") 'plnění zásobníku With objStack .Push ("1. náboj") .Push ("2. náboj") .Push ("3. náboj") End With 'vystřelení 3. náboje 'tj. naposled přidané položky MsgBox objStack.Pop 'vystřelení 2. náboje MsgBox objStack.Pop 'je v zásobníku 1. náboj? MsgBox objStack.Contains("1. náboj") 'odstranění proměnné z paměti Set objStack = Nothing End Sub |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | Sub ProceduraQueue() Dim objQueue 'fronta, také jinak FIFO 'tj. First In First Out (první dovnitř, první ven) Set objQueue = CreateObject("System.Collections.Queue") 'plnění fronty With objQueue .enQueue ("1. člověk") .enQueue ("2. člověk") .enQueue ("3. člověk") End With 'odchod 1. člověka 'tj. odebrání první (nejstarší) přidané položky MsgBox objQueue.Dequeue 'odchod 2. člověka MsgBox objQueue.Dequeue 'kdo je na řadě? MsgBox objQueue.Peek 'odstranění proměnné z paměti Set objQueue = Nothing End Sub |
Příloha
pole_arraylist.zip