Привет! Поделитесь, у кого есть, кодом Fn VBA для 64 битного MS Excel, которая принимает коллекцию как аргумент и возвращает все ее ключи (именно ключи, не значения).
testuser, ну я на тот пост и указал :-) Разве что тс не указал, что в итоге он хочет видеть, коллекцию ключей или массив ключей или массив ключ,значение...
testuser, БМВ, спасибо огромное! То, что нужно! Скажите, а в плане производительности это сопоставимо с Dictiory.keys()? Без учета накладных на первоначальное создание самого объетка Dictiory или коллекции, ключи которого получаем.
Что скажете, подходит ли этот функционал для широкого использования, аналогично Dictiory.keys()? Например. Задумал заменить в своем проекте все Dictionary на Коллекции. Мотивация - опасное поведение Dictionary при обращении к значению, он добавляет ключ, если его не было, даже тогда, когда я предпочел бы ошибку. Проект покрыт проверками Dictionary.Exists с функционалом выброса ошибки, если ключа нет, коллекция делала бы выброс ошибки по-умолчанию, что избавляет меня от нудных танцев с Dictionary и неочевидного Debugа.
Аналог .keys() для коллекций потребовался чтобы не городить дополнительный уровень вложености коллекции, хранящей Row таблицы (в отличии от Dictionary, Row в виде коллекции не может сообщить к каким столбцам она хранит значения из-за чего где-то в верхнеуровневом коде нужно выписывались названия столбцов или же хранить их в общей структуре DSetWithMeta с полями "rows", "columnNames". Т.е. образовался дополнительный уровень вложенности в сравнении с Dictionary).
Пример с Row не единственный, а лишь один частный случай, но очень часто Dictionary подкупает именно тем, что имеет метод .keys(), который в отличии от метода exists() сложно реализовать для коллекции (но благодаря вам, кажется, это теперь стало возможным).
написал: Разве что тс не указал, что в итоге он хочет видеть, коллекцию ключей или массив ключей или массив ключ,значение...
Да это не имеет принципиального значения) Я нуждался в низкоуровневом образце кода с трюком, проверенным практикой, а потому устойчивый к ошибкам, чтобы утащить к себе в проект и видоизменить. Теперь, когда я получил такие образцы благодаря вам, мои мысли оставили это и меня интересует вопрос цены в плане производительности в сравнении с тем же Dictionary.
Сергей Юрьевич написал: опрос цены в плане производительности в сравнении с тем же Dictionary.
Как правило, хватает обычного Dictionary. Все зависит, конечно от задачи, но имхо лучше в алгоритме избегать такого сюжета, когда многократно получается массив ключей или значений, а реализовать это как-то по другому.
testuser, это понятно, что выгрузку ключей лучше переиспользовать. Вопрос был другой - эффективность ColKeys, пример которой вы привели, в плане производительности. Сильно уступает методу keys(), который у Dictionary (при равном наборе ключей и значений)? Или призводительность сопоставима и переписав проект, избавив его от Dictionary, я не получу жесткой просадки производительности в части .keys() функционала? Вы не тестировали ее в плане перформанса?
В моей не очень обильной истории макрописца только однажды коллекция окащалась быстрее, но Коллекция более универсальна при использовании на pc и Mac Позволяет сортировать Пробигало мнение что после 100 000 словарь начинает притормаживать в отличии ит коллекции.
Иными словами, лишние строки кода могут быть компенсированы скоростью, но все зависит от потребеости.
Сергей Юрьевич написал: Или призводительность сопоставима и переписав проект, избавив его от Dictionary, я не получу жесткой просадки производительности в части .keys() функционала? Вы не тестировали ее в плане перформанса?
Конкретно этот момент я не тестировал. Самописная функция выполняемая на vba, компилируемом в режиме p-code, вероятнее всего будет медленей функции из нативно-скомпилированной библиотеки. Плю на x64 vba добавляются жесткие тормоза на вызов Api-функций. Другой вопрос, на сколько это будет медленей, заметно ли это для глазу в каком-то конкретном случае, вы конечно можете это протестировать и т.о. внести какую-то ясность в этом моменте.
Цитата
БМВ написал: Пробигало мнение что после 100 000 словарь
Я однажды экспериментировал с изобретением самописного словаря и заодно сравнил скорость заполнения + поиска в коллекции и словаре случайных строковых ключей. И у меня почему-то коллекции оказывалась сильно быстрей даже на куда меньшем количестве, т.е. 10к очень было заметно. Главное, я думаю учитывать разную реализацию поиска у коллекции - бинарное дерево, от словаря - хеш-таблица. Бинарное дерево лучше заполнять случайными данными, или если данные отсортированы, то заполнять их в случайном порядке. Для хэш-таблицы это не критично, но у нее (конкретно у Dictionary) есть другой недостаток - сама хэш-таблица внутри словаря имеет четко фиксированый размер, это понятно по тому факту, что после определенного колличества ключей, начинает заметно падать скорость поиска.
Добрый день, я немного выпал из форума, может что пропустил. Куда у нас пропал, самый большой любитель замера скорости и экономии миллисекунд Jack Famous?
написал: И у меня почему-то коллекции оказывалась сильно быстрей даже на куда меньшем количестве, т.е. 10к очень было заметно
Если вы создали словарь так:
Код
Dim Dict As Object
Set Dict = CreateObject("Scripting.Dictionary")
То это долгий старт для Dictionary и тогда понятно почему вам приходится говорить о разительной разнице. Для себя решил отказаться от такого способа создания словарей.
написал: Коллекция более универсальна при использовании на pc и MacПозволяет сортировать
В смысле коллекция позволяет сортировать? Вы имеете в виду хранит порядок в котором элементы были добавлены? Dictionary тоже порядок внесения запоминает.
Короче может это уже было но пусть будте. Действительно что-то там после 100000
Скрытый текст
Код
Private Sub DicttVsCollTest()
Const CntElem& = 200000
Const CntIter& = 1
Const minSzStr& = 5 'минимальный размер случайных строк
Const maxSzStr& = 10 'максимальный размер случ. строк
Dim sRndAr$()
sRndAr = GetRndStrArray(CntElem, minSzStr, maxSzStr)
Dim i&, j&, t!, t1!, t2!
Dim Coll As New VBA.Collection
t = Timer
For j = 0 To CntElem - 1
Coll.Add Empty, sRndAr(j)
Next
t1 = t1 + Timer - t
Dim Dict As New Dictionary
t = Timer
For j = 0 To CntElem - 1
Dict.Add sRndAr(j), Empty
Next
t2 = t2 + Timer - t
Debug.Print "Скорость заполнения " & CntElem & " элементов: "
Debug.Print "Коллекция: ", t1
Debug.Print "Словарь: ", t2
Dim vElem
t1 = Timer
For i = 1 To CntIter
For j = 0 To CntElem - 1
vElem = Coll(sRndAr(j))
Next
Next
t1 = Timer - t1
t2 = Timer
For i = 1 To CntIter
For j = 0 To CntElem - 1
vElem = Dict(sRndAr(j))
Next
Next
t2 = Timer - t2
Debug.Print "Получение элементов: "
Debug.Print "Коллекция: ", t1
Debug.Print "Словарь: ", t2
End Sub
Function GetRndStrArray(ByVal Cnt As Long, ByVal minStrSz&, ByVal maxStrSz&) As String()
Cnt = Cnt - 1
Dim i&, sArOut$(): ReDim sArOut(Cnt)
For i = 0 To Cnt
sArOut(i) = GetRandomString(minStrSz, maxStrSz)
Next
GetRndStrArray = sArOut
End Function
Function GetRandomString(ByVal Lw&, ByVal Up&) As String
Static init As Boolean, ChrTbl$, ChrTblLen&
If init Then
Else
ChrTbl = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqastuvwxyzАБВГДЕЁЖЗИЙКЛМНУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрстуфхцчшщьыъэюя "
ChrTblLen = Len(ChrTbl)
Randomize
init = True
End If
Dim i&, j&, strLen&: strLen = (Up - Lw + 1) * Rnd + Lw
GetRandomString = String(strLen, vbNullChar)
For i = 1 To strLen
j = Int(ChrTblLen * Rnd + 1)
Mid$(GetRandomString, i) = Mid$(ChrTbl, j, 1)
Next
End Function
написал: Сергей Юрьевич , нет. Я имею в виду что можно провести сортировку в коллекции. Изменив порядок. Как и в массиве.
Как же вы измените порядок? Если вы попытаетесь перезаписать значение, то получите ошибку.
Код
Dim MyCol As New Collection
MyCol.Add "Апельсины", "ключ1"
MyCol.Item("ключ1") = "Бананы" ' Ошибка
А если вы будете удалять и добавлять элемент заново и таким образом добиваться сортировки (типо сортировки пузырьком, но снизу), то тоже самое можно делать и в Dictionary.
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/add-method-visua... before Optional. An expression that specifies a relative position in the collection. The member to be added is placed in the collection before the member identified by the before argument. If a numeric expression, before must be a number from 1 to the value of the collection's Count property. If a string expression, before must correspond to the key specified when the member being referred to was added to the collection. You can specify a before position or an after position, but not both.
after Optional. An expression that specifies a relative position in the collection. The member to be added is placed in the collection after the member identified by the after argument. If numeric, after must be a number from 1 to the value of the collection's Count property. If a string, after must correspond to the key specified when the member referred to was added to the collection. You can specify a before position or an after position, but not both.