Листая форум наткнулся (в 2016 году, если память не изменяет) на сообщение от Hugo в одной из тем на тему этого объекта. Заинтересовало. Решил провести ряд экспериментов. Интересовала в первую очередь скорость обработки данных и доступный в VBA инструментарий по работе с SortedList. ---------------- Для тех, кто не в курсе SortedList представляет из себя словарь (ключ, значение) сортирующий сам себя по факту наполнения. В качестве значения может сдержать: строки, числа, массивы, объекты. --------------- Разочарование №1 - не доступна в VBA выгрузка ключей/итемов в массив, только циклом. Хотя такие методы есть Разочарование №2 - скорость наполнения (в данном случае и одновременной сортировки) сопоставимо с Dictionary. Но наивно было бы ожидать большую разницу в меньшую сторону. -------------- Тест-драйв по скорости:
Скрытый текст
Тестер:
Скрытый текст
Код
Sub nnn()
Dim SL As Object, a&, b&, c&, arr(), nn&, tt#
For c = 10000 To 100000 Step 10000
Set SL = CreateObject("System.Collections.SortedList")
ReDim arr(1 To c, 1 To 2)
tt = Timer
For a = 1 To c
For b = 1 To 2
nn = Rnd * c: arr(a, b) = nn
Next
Next
tt = Timer - tt: Debug.Print "Generate (" & c & ") time: " & tt
tt = Timer
For a = 1 To c
If Not SL.Contains(arr(a, 1)) Then SL.Add arr(a, 1), arr(a, 2)
Next
tt = Timer - tt: Debug.Print "Fill SortedList (" & c & ") time: " & tt
tt = Timer
ReDim arr(1 To SL.Count, 1 To 2)
For a = 0 To SL.Count - 1
arr(a + 1, 1) = SL.GetKey(a): arr(a + 1, 2) = SL.Item(arr(a + 1, 1))
Next
tt = Timer - tt: Debug.Print "Get to Array (" & c & ") time: " & tt
Next
Set SL = Nothing
End Sub
Результат:
Скрытый текст
Код
Generate (10000) time: 0,00390625
Fill SortedList (10000) time: 0,16015625
Get to Array (10000) time: 0,109375
Generate (20000) time: 0,00390625
Fill SortedList (20000) time: 0,29296875
Get to Array (20000) time: 0,22265625
Generate (30000) time: 0,00390625
Fill SortedList (30000) time: 0,4765625
Get to Array (30000) time: 0,33203125
Generate (40000) time: 0,0078125
Fill SortedList (40000) time: 0,72265625
Get to Array (40000) time: 0,46484375
Generate (50000) time: 0,0078125
Fill SortedList (50000) time: 0,984375
Get to Array (50000) time: 0,5546875
Generate (60000) time: 0,0078125
Fill SortedList (60000) time: 1,3125
Get to Array (60000) time: 0,6953125
Generate (70000) time: 0,0078125
Fill SortedList (70000) time: 1,625
Get to Array (70000) time: 0,80859375
Generate (80000) time: 0,01171875
Fill SortedList (80000) time: 1,99609375
Get to Array (80000) time: 0,90234375
Generate (90000) time: 0,0234375
Fill SortedList (90000) time: 2,40234375
Get to Array (90000) time: 1,02734375
Generate (100000) time: 0,015625
Fill SortedList (100000) time: 2,81640625
Get to Array (100000) time: 1,11328125
На миллионе SortedList завис минут на 10. ----- В общем для небольших массивов пойдет. ---------------------------------------------------------------- Список доступных методов в VBA:
Add - добавление пары ключ/значение Item - чтение/запись значения по ключу, или перезапись значения ключа Count - чтение - кол-во пар в SortedList Capacity - чтение/установка количества элементов объекта
Примеры:
Скрытый текст
Код
SL.Add "aaa", [A1] 'в данном случае записывается не ссылка на ячейку в виде объекта, а только ее содержимое
SL.Add "bbb", CreateObject("Scripting.Dictionary")
SL.Add "ccc", Array(1, 2, 3)
SL.Item("ddd") = 123
SL.Item("ddd") = 456
b = SL.Item("ddd")
a = SL.Capacity
SL.Capacity = 10
Clear - очистка объекта Clone - создание копии объекта Contains (Key) - проверка наличия определенного ключа в SortedList ContainsKey (Key) - проверка наличия определенного ключа в SortedList, т.е. тоже самое что и предыдущее ContainsValue (Value) - проверка наличия определенного элемента в SortedList. Не ключа. Полезная штука Equals(Object) - сравнение на идентичность двух объектов (например двa SortedList) GetByIndex(id) - добыча значения по индексу GetKey(id) - взять ключ по его индексу IndexOfKey(Key) - получаем индекс по ключу IndexOfValue(Value) - индекс по значению Remove(Key) - удаление пары ключ/элемент по ключу TrimToSize - подгонка пар ключ/элемент под определенное кол-во. В теории полезно только если был установлен завышенный размер массива элементов SortedList
--------------------------------------------------------------- Пример сортера на основе SortedList с примером же его использования:
Скрытый текст
Код
Sub aaa()
Dim a&, b&, c&, arr(), nn&, tt#, x&
c = 10000: x = 10
ReDim arr(1 To c, 1 To x)
For a = 1 To c
For b = 1 To x
nn = Rnd * c: arr(a, b) = nn
Next
Next
SLSort 1, arr()
End Sub
'--------------------------------------------
Sub SLSort(ByVal n%, arr())
Dim dd&(), a&, b&, SL As Object, iArr(), sp&(), gg&(), c&, z&, x&
Set SL = CreateObject("System.Collections.SortedList")
b = 0: c = 0: x = LBound(arr)
For a = x To UBound(arr)
If Len(arr(a, n)) > 0 Then
b = b + 1: ReDim Preserve gg(1 To b): gg(b) = a
Else
c = c + 1: ReDim Preserve sp(1 To c): sp(c) = a
End If
Next
For a = 1 To b
If Not SL.Contains(arr(gg(a), n)) Then
ReDim dd(1 To 1): dd(1) = a: SL.Add arr(gg(a), n), dd
Else
dd = SL.Item(arr(gg(a), n)): ReDim Preserve dd(1 To UBound(dd) + 1)
dd(UBound(dd)) = a: SL.Item(arr(gg(a), n)) = dd
End If
Next
ReDim iArr(x To UBound(arr), LBound(arr, 2) To UBound(arr, 2))
If b > 0 Then
For a = 0 To SL.Count - 1: dd = SL.GetByIndex(a)
For b = 1 To UBound(dd)
For z = LBound(arr, 2) To UBound(arr, 2)
iArr(x, z) = arr(dd(b), z)
Next: x = x + 1
Next
Next
End If
If c > 0 Then
For a = 1 To c
For z = LBound(arr, 2) To UBound(arr, 2)
iArr(x, z) = arr(sp(a), z)
Next: x = x + 1
Next
End If
Set SL = Nothing: arr = iArr: Erase iArr: Erase dd: Erase sp: Erase gg
End Sub
bedvit, ArrayList позволяет выгрузить все ключи в массив одним махом) SortedList - нет. Ну или я пока не дорылся до метода, с помощью которого это возможно (CopyTo(), GetKeyList() не работают в VBA).
Anchoret, да, не заметил сразу - это разные контейнеры. SortedList - не пользовался, но сейчас на своем примере протестировал. Медленный даже для VBA. Загрузить и выгрузить массивом, штатно, тоже не выйдет.