Расскажите или укажите, есть ли где сравнительное сопоставление трех понятий: массив, коллекция, словарь. Хочу понять, когда и зачем их лучше использовать, в чем общее, в чем различие.
Общее: по сути это все массивы. Различия: дофига. У коллекций свой набор методов, у словарей свой. У массивов в чистом виде по большому счету нет ничего. Но применимо к VBA чисто массив - arr() - можно заполнить очень быстро без цикла значением диапазона ячеек или формулами. Словари и коллекции требуют обязательного цикла для добавления элементов. Преимущество коллекций(New Collection) - могут использоваться и в Windows и в MAC. А словари - только в Windows. Так же при добавлении элемента в коллекцию можно указать куда поместить новый элемент: до или после. Это дает возможность делать быструю сортировку уникальных значений. Преимущество словарей: есть проверка наличия ключа встроенным свойством(Exists), что позволяет работать с ними быстрее. Так же можно настроить методы сравнения текста через свойство CompareMode. Если установить как 1 - то регистр не будет учитываться методом Exists при сравнении имеющихся в словаре элементов.
Но однозначно сказать что лучше, а что хуже нельзя. Все зависит от ситуации.
Например, в некотором цикле будут собираться данные вида: Артикул1 Наименование1 число1 число2 ... число15 Артикул1 Наименование1 другоечисло1 другоечисло2 ... другоечисло15 Артикул2 Наименование1 число1 число2 ... число15 Артикул2 Наименование2 число1 число2 ... число15 ...
Используя язык баз данных, пара значений "Артикул" и "Наименование" являются ключом для каждой строки массива данных. На каждой итерации получения строки данных надо в некий тип данных(массив, коллекция, словарь) вносить получаемые значения таким образом: 1. если в хранилище нет пары с ключом артикул+наименование, то надо в него вносить получаемую строку 2. если уникальная пара уже есть в хранилище, то надо к хранящимся числовым значениям прибавить числовые значения новой строки, используя данные об артикуле и наименовании
Вопрос - в данной задаче надо использовать какой из типов данных?
ОГРОМНЫМ плюсом словарей является наличие в них методов Items и Keys возвращающих "одним махом" массивы ЗНАЧЕНИЙ и КЛЮЧЕЙ словаря Да и вообще, у коллекций всего 1 свойство (.Count) и 4 метода (.Add .Item .Remove .Clear), а у словарей 4 свойства (.CompareMode .Count .Item .Key) и 6 методов (.Add .Exists .Items .Keys .Remove .RemoveAll), что придаёт работе с ними значительно большую гибкость. По приведённой выше ссылке я выкладывал файл-шпаргалку со свойствами, методами и примерами работы со словарями.
С уважением, Алексей(ИМХО: Excel-2003 - THE BEST!!!)
Так что уникальное? Похоже, что Артикул? Ну и используйте их как ключи к значениям (записям) словаря. А в каждой записи могут лежать как массивы, так и подчинённые словари. Там по ссылке есть пример использования словаря словарей. Добавление ключа с пустой записью происходит автоматически при попытке обращения к словарю по отсутствующему ключу. Единственный минус словарей по сравнению с коллекциями - это отсутствие у метода .Add опциональных параметров [Before | After], которые позволяют достаточно просто производить сортировку записей внутри коллекции. Но это нужно, имхо, достаточно редко.
С уважением, Алексей(ИМХО: Excel-2003 - THE BEST!!!)
Доброе время суток. Со словарями есть один не приятный момент, столкнулся случайно. Если выполнить
Код
Dictionary.RemoveAll
Set Dictionary = Nothing
, то это не приводит к автоматическому освобождению объектов-значений словаря. Они как-бы существуют вплодь до принудительного End, даже не до завершения метода, в котором создавался словарь. С коллекциями такого не происходит.
Как-то я никогда особо освобождением памяти не заморачивался, хотя словари люблю и использую часто... Обычно использую не явное позднее связывание типа
Код
With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare ' создаем временный словарь
…
End With
Никогда никаких проблем не возникало. Может быть, при таком связывании их просто нет? Или просто задачи не настолько тяжёлые, чтобы память ощутимо отожрать?
Алексей, дело не в памяти - её хватало. А вот блокировка объектов не снималась. Пришлось делать вариант на Collection. Столкнулся не в Excel - в VBA IBM Rational System Architect.
Андрей VG написал: А вот блокировка объектов не снималась
Я вот тоже буквально сегодня заметил нечто подобное. Если для словаря используется раннее связывание словарь объявляется переменной (Dim dic1: Set dic1 = CreateObject("Scripting.Dictionary")), то наблюдаются какие-то глюки при попытке добавить НЕ уникальный ключ. С конструкцией With CreateObject("Scripting.Dictionary") такого не происходит
Sanja написал: используется раннее связывание (Dim dic1: Set dic1 = CreateObject("Scripting.Dictionary")
Сёма, это-таки позднее связывание Раннее будет так:
Код
Dim dic1: Set dic1 = New Scripting.Dictionary
А при случае использования With очищение памяти от объектов происходит более корректно, когда-то мы вроде это обсуждали уже. Это касается не только словарей, кстати.
The_Prist написал: Не забывайте отписывать в своих темах...
Похоже, что Дмитрий у нас провидец... borro заварил кашу и исчез. А мы тут его о чём-то спрашиваем, что-то советуем, дискуссию о высоких материях ведём...
С уважением, Алексей(ИМХО: Excel-2003 - THE BEST!!!)
Да есть в этом RSA возможность делать перекрёстную связь между объектами. Пользователь добавляет ссылку с родительского объекта на дочерний и у дочернего появляется в свойствах ссылка на родительский. Соответственно, в VBA нужно ссылки добавлять только с одной стороны, иначе, так как объекты (родительский и дочерний) при их создании открыты на редактирование, то невозможно сохранить не тот не другой. При загрузке же данных описание связей идёт как попало. Вот я и сделал поиск родительского объекта для дочерних через словарь. Сохранил родительские, очистил словарь. Стал сохранять дочерние с установленными ссылками на родительские, а RSA выбрасывает объект заблокирован. Переделал на коллекции - ушло.
Доброго утра. Спасибо, Sanja за совет. Дело в том, что остальные обсуждения моего последнего вопроса не касались, поэтому я молчал. Да и что отвечать, тут только впитывать информацию. Простите, если что не так
borro написал: Дело в том, что остальные обсуждения моего последнего вопроса не касались
А вопрос был какой последний?
Цитата
borro написал: Вопрос - в данной задаче надо использовать какой из типов данных?
Вы все же получили после этого ответ от Alex_ST - словари.
Цитата
Alex_ST написал: Посмотрите в топике Dictionary - это совсем не сложно!
Но отписаться понятно-непонятно, оно-не оно уже не посчитали нужным. А между тем это проявление элементарной вежливости и уважения к отвечающим - отписаться ответившему: помогло - не помогло, понятно - не понятно и т.п. Чтобы все понимали имеет ли смысл дальше что-то предлагать или обсуждать. Т.к. Вы этого не делаете - тема развивается своим ходом, а Вас берут на заметку - типа это тот человек, который темы создает, ответы получает и сваливает. В результате что будет? Правильно. Вам просто перестанут отвечать, ибо потребительское отношение не нравится никому...
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
Alex_ST написал: ОГРОМНЫМ плюсом словарей является наличие в них методов Items и Keys возвращающих "одним махом" массивы ЗНАЧЕНИЙ и КЛЮЧЕЙ словаря
- Microsoft не обещает точное соответствие этих двух массивов, т.е. вываливать их рядом небезопасно. В ответственных задачах нужно к каждому ключу получать значение в индивидуальном порядке. Да и transpose на больших объёмах может сглючить...
Изменено: Hugo - 28.01.2017 12:01:49(буковка потерялась...)
Не совсем по теме, но близко )) Недавно столкнулся с тем, что перебор коллекции циклом работает очень медленно: раньше приходилось обрабаывать относительно небольшие по размеру коллекции, а тут попалась довольно большая. Так вот: уже после 1000-го элемента коллекции увидел, что процесс "не летает" )) А нужно было перебрать порядка 30 000 элементов. ZVI подсказал, что не следует перебирать коллекции по индексу (For i = 1 to Коллекция.Count) - скорость нелинейно падает. Для перебора коллекции следует использовать цикл For Each - Next. Переделал - перемена поразительна! Лично я этого не знал - может кому ещё пригодится )
Юрий М, очень пригодилось, спасибо! Единственно от себя дабавлю - это также справедливо и для словарей. Вложенный цикл по двум словарям (для каждого элемента первого перебирались все элементы второго, 3000 и 1500 элементов соответственно) - for j=0 to count просто "умер", после замены на for each - даже не заметно на фоне остальных операций
Юрий М написал: Лично я этого не знал - может кому ещё пригодится )
Что-то я этот совет Юрия либо пропустил, либо просто забыл... Сейчас практически не программирую. Но несколько лет назад всё равно почему-то предпочитал в своих разработках применять циклы For Each - Next. Наверное, интуитивно
С уважением, Алексей(ИМХО: Excel-2003 - THE BEST!!!)
Alex_ST: почему-то предпочитал в своих разработках применять циклы For Each - Next
они надёжнее, позволяют собирать новый или изменять текущий массив по имеющемуся в цикле индексу. Например, цикл по тысячам областей (фильтр столбца по видимым) нельзя делать через For Each, потому что будет ошибка.
Честно говоря, есть сомнения по поводу скорости перебора словаря (коллекции не использую). Может, при позднем подключении, если только (я раннее использую). Тестов не вижу))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Действительно, перебор по индексам "в лоб" - не для словарей. Не понимаю, зачем это может быть нужно, но, если всё-таки нужно, то взять массивы из словаря и перебирать их будет многократно (на примере — в 8 раз для 100 тыс ключей) быстрее
Option Base 1
Option Explicit
Option Private Module
'====================================================================================================
Sub Test()
Dim dic As New Dictionary
Dim x, aKey, aItem, t!, n&, res&
t = Timer
For n = 1 To 100000 ' время для 100 тыс элементов, иначе словарю худо будет
dic.Add n, Format$(n, "000000")
Next n
Debug.Print Format$(Timer - t, "0.00"), "Fill" ' 0.24
t = Timer
For Each x In dic.Keys
res = x
res = dic(x)
Next x
Debug.Print Format$(Timer - t, "0.00"), "Each" ' 0.25
t = Timer
aKey = dic.Keys: aItem = dic.Items
For n = LBound(aKey) To UBound(aKey)
res = aKey(n)
res = aItem(n)
Next n
Debug.Print Format$(Timer - t, "0.00"), "Array" ' 0.03 (в 8 раз быстрее с учётом получения массивов)
Exit Sub
t = Timer
For n = 0 To dic.Count - 1 ' НЕ БОЛЕЕ 10 (НЕ 100) тыс элементов иначе кабздец такому перебору
res = dic.Keys(n)
Next n
Debug.Print Format$(Timer - t, "0.00"), "To" ' 1.88 для 10 тыс. Остальные счётчики по нулям
End Sub
'====================================================================================================
'====================================================================================================
При раннем связывании, разница в соответствии "ключ-значение" в массивах при их получении из словаря, не замечена. При позднем - я не уверен. При этом ПОРЯДОК РАСПОЛОЖЕНИЯ ПАР элементов в словаре, вполне может не соответствовать их ПОРЯДКУ при НАПОЛНЕНИИ словаря
Что я имею в виду
Код
Sub t()
Dim dic As New Dictionary, x
Dim x, arr(), i&
arr = Array(0, 1, 2, 3, 4, 5)
For i = 0 To UBound(arr)
dic(i) = "Item " & i
Next i
'dic.Keys(i) вообще не факт что равен arr(i)
End Sub
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Jack Famous написал: 'dic.Keys(i) вообще не факт что равен arr(i)
Добрый день, Алексей. Вы же сами в коде создали ключи словаря, начиная с нулевого, а не с первого, как в значении начального элемента массива. В массиве точно так же значения массива, не совпадают с индексом массива: arr(0) <> 0 Это ошибка в представлении о логике кода, а не проблема словаря. Код должен быть, например таким:
Код
Sub t()
Dim dic As New Dictionary
Dim arr(), i&
arr = Array(0, 1, 2, 3, 4)
For i = LBound(arr) To UBound(arr)
dic(i) = "Item " & i
Debug.Print dic.Keys(i) = arr(i), dic.Keys(i), arr(i)
Next
End Sub
' Или таким
Sub t1()
Dim dic As New Dictionary
Dim arr(), i&
arr = Array(1, 2, 3, 4, 5)
For i = LBound(arr) To UBound(arr)
dic(arr(i)) = "Item " & i
Debug.Print dic.Keys(i) = arr(i), dic.Keys(i), arr(i)
Next
End Sub
Цитата
Jack Famous написал: При этом ПОРЯДОК РАСПОЛОЖЕНИЯ ПАР элементов в словаре, вполне может не соответствовать их ПОРЯДКУ при НАПОЛНЕНИИ словаря
Это утверждение некорректное, так как касается внутреннего механизма работы словаря, а не его документированного внешнего интерфейса (свойств и методов .Item, .Keys, .Values и др.) Словари всегда обеспечивают соответствие в массивах .Keys и .Values порядку заполнения словаря. В словаре всегда доступ по ключу соответствует доступу по индексу. Об этом мы в теме по Вашей 2-й ссылке уже общались - здесь.
ZVI, приветствую! Всегда рад видеть вас в своих (и не только) темах
Цитата
ZVI: Вы же сами в коде создали ключи словаря, начиная с нулевого, а не с первого, как в значении начального элемента массива
спасибо, согласен, оплошал, поправил
Цитата
ZVI: Словари всегда обеспечивают соответствие в массивах .Keys и .Values порядку заполнения словаря … уже общались
там были только тесты, а хотелось бы увидеть документальное подтверждение, ведь никакими тестами нельзя доказать правило, а можно только приближаться к нему. А вот когда в докУменте будет написано — другое дело. Во всяком случае, логика Виталия мне понятна: они сказали, что это аналог перловых таблиц, у перловых таблиц порядок сбора и хранения не соответствует, а значит и у словарей тоже. Тестами пытался повторить, но не вышло - пока что всегда соответствует
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Добрый вечер, Алексей. Гипотеза - это предположение для объяснения каких-то явлений. Но явлений-то в данном случае и нет. Слова Виталия, в принципе, могут касаться только внутреннего устройства словаря, а не его внешнего интерфейса (см. моё сообщение выше). Но т.к. и Вы, и Виталий на форуме - авторитеты, то подобное утверждение про словари запросто может кого-то ввести в заблуждение. Чего не хотелось бы. Собственно, поэтому и подключаюсь в тему.