Страницы: 1
RSS
Изменение массива, являющегося значением Dictionary, Правильный способ изменить значение Dictionary, которое является динамическим массивом
 
Здравствуйте.
В процессе процедуры формирую Dictionary, в котором текстовым ключам соответствуют наборы данных. Эти наборы надо изменять, и наиболее логичным представляется динамический массив.
Примерный код, который я хотел бы видеть:
Код
Sub test()
    Dim test_dict As Object
    Set test_dict = CreateObject("Scripting.Dictionary")
    Dim start_vals_arr() As Single
    ReDim start_vals_arr(0)
    start_vals_arr(0) = 15.87
    test_dict.Add "Test_key", start_vals_arr
    
    aaa = test_dict.Item("Test_key")
    
    ReDim Preserve aaa(1)
    aaa(1) = 48.56
    test_dict.Item("Test_key") = aaa
    
    'для Watches
    bbb = test_dict.Item("Test_key")
    
End Sub

Он не работает, выдаёт ошибку ReDim.

В принципе, удалось заставить работать грандиозный костыль с объявлением статического массива длиной (старый + 1) и копированием в него всё содержимое старого + новое значение, но это реально грандиозный костыль. Подскажите пожалуйста, есть ли более человеческий способ добраться до динамического массива, который является значением словаря, и редимить/изменять значения в нём?

 
Объявите aaa As Variant
 
Работает и с single - массивами
Код
Sub test()
    Dim a() As Single, b() As Single
    Dim start_vals_arr() As Single
    Dim test_dict As Object
    Set test_dict = CreateObject("Scripting.Dictionary")
    ReDim start_vals_arr(0)
    start_vals_arr(0) = 15.87
    test_dict.Add "Test_key", start_vals_arr
    
    a = test_dict.Item("Test_key")
    
    ReDim Preserve a(1)
    a(1) = 48.56
    test_dict.Item("Test_key") = a
    
    'для Watches
    b = test_dict.Item("Test_key")
    
End Sub
 
Похожий вопрос
Изменение элемента массива, являющегося элементом словаря
Согласие есть продукт при полном непротивлении сторон
 
Цитата
написал:
Похожий вопрос
Спасибо всем ответившим!
Странно, что я не нашёл тему по ссылке, хотя честно пробовал.
 
Сергей, В зависимости от задачи - если например нужно только собирать значения - можно вместо массива собирать в словаре коллекцию значений, не нужно будет извлекать и редимить что тормоза.
Ещё как вариант - создать внешний массив нужной размерности, и хранить в словаре только индекс этого массива - тогда по  индексу легко получить координаты значений в массиве.
 
Спасибо за подсказку, именно так и сделал.
Осталось только понять почему код ниже не работает, (то что закомментировано работает, но это понимать не нужно))
Код
Sub test2()
    Dim test_dict_dict As Object
    Set test_dict = CreateObject("Scripting.Dictionary")
    Dim start_vals_coll As New Collection
    start_vals_coll.Add 1.15
    test_dict.Add "name", start_vals_coll
    
    Dim exist_vals_coll As New Collection
    Set exist_vals_coll = test_dict.Item("name")
    exist_vals_coll.Add 1.16
    test_dict.Item("name") = exist_vals_coll 'Ошибка 450
    
    'test_dict("name").Add 1.16 'А это работает
    
End Sub
 
Вам необходимо указать конкретный (с определенным номером) элемент коллекции, например:
Код
test_dict.Item("name") = exist_vals_coll(1)
 
Сергей, там вот так можно дополнять коллекцию в словаре:
Код
            If Not .exists(t) Then .Add t, New Collection
            .Item(t).Add значениеколлекции

t = ключ словаря

P.S.
Код
Sub test3()
    Dim test_dict As Object, exist_vals_coll As Object, t$, el
    
    Set test_dict = CreateObject("Scripting.Dictionary")

    With test_dict
        t = "name"
        If Not .exists(t) Then .Add t, New Collection
        .Item(t).Add 1.15
        .Item(t).Add 1.16
    End With

    Set exist_vals_coll = test_dict.Item("name")

    For Each el In exist_vals_coll
        MsgBox el
    Next

End Sub
Изменено: Hugo - 06.04.2025 22:23:05
 
Код
Sub test2_2()
    Dim dic As Object, evc As New Collection, svc As New Collection
    Dim chto
    
    svc.Add 1.15
    chto = svc(svc.Count)
    Debug.Print "svc(" & svc.Count & ") = "; chto
    
    Set dic = CreateObject("Scripting.Dictionary")
        dic.Add "name", svc
        chto = dic("name")(svc.Count)
        Debug.Print "dic(" & dic.Count & ") = dic(""name"") = "; chto
        
    evc.Add dic.Item("name")
    chto = evc(evc.Count)(dic.Count)
    Debug.Print "evc(" & evc.Count & ") = "; chto
    
    evc.Add 116.16
    chto = evc(evc.Count)
    Debug.Print "evc(" & evc.Count & ") = "; chto
    
        If dic.Exists("name") Then dic.Item("name") = 1.22
        chto = dic("name")
        Debug.Print "dic(" & dic.Count & ") = dic(""name"") = "; chto
End Sub
 
Цитата
написал:
Вам необходимо указать конкретный (с определенным номером) элемент коллекции
Так нет же, значениями словаря у меня является коллекция, а не элемент. И таковая структура нормально работает, если обращаться к ней так, как закомментировано в моём примере. А при попытке присвоить новое значение методом Item словаря, возникает ошибка. Т.е. мой вопрос не в том, какой костыль написать для обхода этого непонятного мне эффекта, а в том, почему так происходит. Вот более наглядно:
Код
Sub test2()
    Dim test_dict_dict As Object
    Set test_dict = CreateObject("Scripting.Dictionary")
    
    Dim first_coll As New Collection
    first_coll.Add 1.15
    
    test_dict.Add "name", first_coll 'добавил в словарь по ключу "name" первую коллекцию
    
    Dim second_coll As New Collection
    second_coll.Add 1.16
    
    test_dict.Item("name") = second_coll 'При попытке назначить другую коллекцию в значение этого ключа - Ошибка 450
    
End Sub
 
К делу не относится, но Вы объявляете переменную Dim test_dict_dict As Object, а словарь - test_dict
По теме
Т.к. элемент Словаря это Коллекция, т.е. объект, то и значение ему(элементу) нужно присваивать как объекту, т.е. через Set
Код
Sub test2()
    Dim test_dict As Object
    Dim first_coll As New Collection
    Dim second_coll As New Collection
    
    Set test_dict = CreateObject("Scripting.Dictionary")
    
    first_coll.Add 10
    
    test_dict.Add "iKey", first_coll
    
    second_coll.Add 20
    
    Set test_dict("iKey") = second_coll
    
End Sub
Изменено: Sanja - 08.04.2025 04:13:45
Согласие есть продукт при полном непротивлении сторон
 
Цитата
Сергей написал:
test_dict.Item("name") = second_coll
В начале этой строки пропущен оператор Set, т.к. в .Item переопределяется объект коллекции, а не просто значение:
Set test_dict.Item("name") = second_coll
А метод .Add, в отличие от .Item, добавляет что угодно (объект или значение)
Изменено: ZVI - 08.04.2025 06:27:55
 
Цитата
Sanja написал:
но Вы объявляете переменную
Ошибку сделал при переносе и форматировании листинга сюда, на форум.
Цитата
нужно присваивать как объекту, т.е. через Set
Sanja , ZVI, спасибо вам! Это и есть ответ на заданный вопрос!

К делу не относится, но vba это весьма странный и нелогичный язык (после работы с gs от google).
Изменено: Сергей - 08.04.2025 20:57:32
 
Цитата
Сергей написал:
vba это весьма странный и нелогичный язык (после работы с gs от google).
Это наоборот логично, что процедура передачи ссылки обозначается чуть по другому, чем простое присвоение. "Gs" (без гугл) сам по себе это тоже очень странный язык, об этом говорят сплошь и рядом.
Страницы: 1
Читают тему
Наверх