Добавить элементы в массив в словаре

У меня есть словарь, и я хочу добавить новые строки к элементам. Моя идея состоит в том, чтобы создать список строк как item для каждого key.

Мой код до сих пор:

Sub AccountEntitlements()

    Dim sh1 As Worksheet
    Dim acc As Worksheet
    Dim arr() As Variant
    Dim d As Variant
    Dim i As Long
    Dim count As Long

    Set sh1 = Sheets("Sheet1")
    Set acc = Sheets("accountsentitlements")
    Set d = CreateObject("Scripting.Dictionary")

    arr = sh1.Range("D:F")

    For i = LBound(arr) To UBound(arr)
        If d.Exists(arr(i, 3)) Then
            ReDim Preserve arr(UBound(arr) + 1) '<- Error line
            d(arr(i, 3)) = Array(arr(i, 1))
        Else
            d.Add Key:=arr(i, 3), Item:=Array(arr(i, 1))
        End If

    Next i

    For count = 1 To d.count - 1
        acc.Cells(count + 1, "D").Value = UCase(d.Keys()(count))
        acc.Cells(count + 1, "E").Value = d.Items()(count)
    Next count

End Sub

сообщение об ошибке — это Run-time error '9': Subscript out of range.

Важным блоком кода является

For i = LBound(arr) To UBound(arr)
     If d.Exists(arr(i, 3)) Then
          ReDim Preserve arr(UBound(arr) + 1) '<- Error line
          d(arr(i, 3)) = Array(arr(i, 1))
     Else
          d.Add Key:=arr(i, 3), Item:=Array(arr(i, 1))
     End If

Ключ словаря — это учетная запись пользователя, а элементы должны быть их группами членства. Пример:

Key= ABCD , Item= Entitlement1, Entitlement2, etc.

Как можно расширить массив элементов и включить в него предыдущие записи?

Используйте словарь или коллекцию вместо массива для хранения групп членства. И зачем вообще создавать такой большой массив для перебора?

Ron Rosenfeld 25.03.2019 11:36

Ошибка в том, что вы можете Redim Preserve только последний элемент многомерного массива. Поскольку вы уже arr= Range("D:F"), and your Redim Preserve arr(...` оператор должен завершиться ошибкой. Он НЕ действует на массив в словаре.

Ron Rosenfeld 25.03.2019 11:42

@RonRosenfeld, что вы имеете в виду под «такой большой массив»? Как бы вы разделили массив?

Alex_P 25.03.2019 11:59
arr = Range("D:F") создает массив измерений (1 to 1048576, 1 to 4). В вашей базе данных столько элементов? Хорошее обсуждение см. в недавней статье Чипа Пирсона на Массивы и диапазоны в VBA.
Ron Rosenfeld 25.03.2019 12:02

@RonRosenfeld, у меня 81 000 строк. Спасибо за ссылку. Я это проверю.

Alex_P 25.03.2019 12:04

Итак, зачем вам массив в двенадцать раз больше? Прохождение цикла займет намного больше времени.

Ron Rosenfeld 25.03.2019 12:05

@RonRosenfeld, большое спасибо за ваши комментарии. Теперь я просто соединил строки в своем словаре и установил длину массива, соответствующую моим данным. Спасибо еще раз!

Alex_P 25.03.2019 15:50
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
7
273
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Среди прочих проблем:

Вы можете только ReDim последний элемент многомерного массива.

Ваша линия

arr = sh1.Range("D:F")

создаст 2D-массив на основе 1: arr(1 to 1048576, 1 to 4). Если у вас есть база данных с более чем 4*10^6 элементами, вы можете рассмотреть другой инструмент.

Таким образом, допустимая команда может быть

Redim Preserve arr(1 to ubound(arr,1), 1 to ubound(arr,2)+1)

Но это не то, что ты делаешь. Чтобы выполнить то, что вы хотите сделать, попробуйте что-то вроде этого:

For i = LBound(arr) To UBound(arr)
    If d.Exists(arr(i, 3)) Then
        X = d(arr(i, 3))
        ReDim Preserve X(UBound(X, 1) + 1)
        X(UBound(X, 1)) = arr(i, 1)
        d(arr(i, 3)) = X
    Else
        d.Add Key:=arr(i, 3), Item:=Array(arr(i, 1))
    End If    
Next i

Но почему бы просто не использовать Dictionary или Collection для хранения списка элементов. Тогда вам вообще не нужно беспокоиться об изменении размера массива.

Ответ принят как подходящий

Большое спасибо за вашу помощь (@Ron Rosenfeld)!

Ниже моя последняя часть кода.

For i = LBound(arr) To UBound(arr)
    If d.Exists(arr(i, 3)) Then
        d(arr(i, 3)) = d.Item(arr(i, 3)) & "," & arr(i, 1)
    Else
        d.Add Key:=arr(i, 3), Item:=arr(i, 1)
    End If
Next i

Я все еще проверял, следует ли мне объединять строки с помощью & "," & или с помощью функции JOIN(), но в конце концов остановился на первом варианте.

Что касается размера моего массива, я добавил счетчик строк, чтобы он соответствовал длине массива. lrow = sh1.Cells(Rows.count, "D").End(xlUp).Row.

Другие вопросы по теме