Как назначить диапазон и массив 1d массиву вариантов 2d?

Я работаю над конкретной проблемой, когда мне приходится читать несколько столбцов из «листа» в «файле». Эти столбцы должны временно храниться в «fileArray» и после некоторых операций переноситься в «masterFile».

По сути, диапазон содержит около 40 тысяч значений для каждого столбца, который я хочу назначить fileArray (от 1 до 4).

Я получаю сообщение об ошибке «Индекс вне диапазона» каждый раз, когда пытаюсь присвоить значения fileArray.

                ReDim fileArray(1 To 4, 1 To fileLastRow - 1)
                Dim arr As Variant
                ' Copy all relevant columns from sheet
                arr = Flatten(sheet.Range(sheet.Cells(2, fileKeyColumn), sheet.Cells(fileLastRow, fileKeyColumn)))
                
                fileArray(1) = arr ' Keep getting subscript out range errors here
                AssignVal fileArray, 1, sheet.Range(sheet.Cells(2, fileKeyColumn), sheet.Cells(fileLastRow, fileKeyColumn))
                If fileTF1Column <> 0 Then fileArray(2) = Flatten(sheet.Range(Cells(2, fileTF1Column), Cells(fileLastRow, fileTF1Column)).value)
                If fileTF2Column <> 0 Then fileArray(3) = Flatten(sheet.Range(Cells(2, fileTF2Column), Cells(fileLastRow, fileTF2Column)).value)
                If fileTF3Column <> 0 Then fileArray(4) = Flatten(sheet.Range(Cells(2, fileTF3Column), Cells(fileLastRow, fileTF3Column)).value)
         

Я попытался присвоить значение напрямую как fileArray(1) = sheet.Range(sheet.Cells(2, fileKeyColumn), sheet.Cells(fileLastRow, fileKeyColumn))

и

fileArray(1) = sheet.Range(sheet.Cells(2, fileKeyColumn), sheet.Cells(fileLastRow, fileKeyColumn)).value

Я также попробовал использовать оператор Set.

Когда это не сработало, я адаптировал функцию Flatten из сообщения, которое нашел на Stack Overflow, для преобразования диапазона в одномерный массив. Я попытался назначить его непосредственно «fileArray(1)» и через временную переменную «arr».

Я даже пытался создать функцию AssignVal для перебора диапазона и присвоения значения массиву.

Пока ничего не получается, и мой срок быстро приближается. Я не могу понять, что я делаю не так. Может кто-то помочь мне с этим? Также, пожалуйста, объясните логику, чтобы я мог понять это сам в следующий раз. Спасибо!

Public Function Flatten(inputRange As Range) As Variant()
    'Adapted from code found at https://stackoverflow.com/questions/37689847/creating-an-array-from-a-range-in-vba
    
    Dim out() As Variant
    ReDim out(1 To inputRange.Rows.count)

    Dim i As Long
    For i = 1 To inputRange.Rows.count
        out(i) = inputRange(i, 1) 'loop over a range "row"
    Next

    Flatten = out
End Function
Public Sub AssignVal(ByRef inputVar() As Variant, ByVal index As Integer, ByVal inputRange As Range)
    'Adapted from code found at https://stackoverflow.com/questions/37689847/creating-an-array-from-a-range-in-vba
    
    Dim i As Long
    
    If UBound(inputVar, 2) = inputRange.Rows.count Then
    
    For i = 1 To inputRange.Rows.count
        Set inputVar(index)(i) = inputRange(i, 1).value 'loop over a range "row"
    Next
    
    End If

End Sub

Обновлено:

Я обнаружил, что ссылаюсь на массив как на словарь в AssignVal, что и вызывает проблему. Фиксированный код находится здесь на случай, если у кого-то возникнет аналогичная проблема. Я оставляю этот вопрос открытым в надежде найти более элегантный ответ.

                ReDim fileArray(1 To 4, 1 To fileLastRow - 1)
                
                ' Copy all relevant columns from sheet
                
                With sheet
                    AssignVal fileArray, 1, Flatten(.Range(.Cells(2, fileKeyColumn), .Cells(fileLastRow, fileKeyColumn)))
                    If fileTF1Column <> 0 Then AssignVal fileArray, 2, Flatten(.Range(.Cells(2, fileTF1Column), .Cells(fileLastRow, fileTF1Column)))
                    If fileTF2Column <> 0 Then AssignVal fileArray, 3, Flatten(.Range(.Cells(2, fileTF2Column), .Cells(fileLastRow, fileTF2Column)))
                    If fileTF3Column <> 0 Then AssignVal fileArray, 4, Flatten(.Range(.Cells(2, fileTF3Column), .Cells(fileLastRow, fileTF3Column)))
                End With

Используемые заключительные процедуры:

Public Function Flatten(inputRange As Range) As Variant()
    'Adapted from code found at https://stackoverflow.com/questions/37689847/creating-an-array-from-a-range-in-vba
    
    Dim out() As Variant
    ReDim out(1 To inputRange.Rows.count)

    Dim i As Long
    For i = 1 To inputRange.Rows.count
        out(i) = inputRange(i, 1) 'loop over a range "row"
    Next

    Flatten = out
End Function

Public Sub AssignVal(ByRef inputVar() As Variant, ByVal index As Integer, ByRef inputVarArr() As Variant)
    'Adapted from code found at https://stackoverflow.com/questions/37689847/creating-an-array-from-a-range-in-vba
    
    Dim i As Long
    
    If UBound(inputVar, 2) = UBound(inputVarArr) Then
    
    For i = 1 To UBound(inputVar, 2)
         inputVar(index, i) = inputVarArr(i) 'loop over a range "row"
    Next
    
    End If

End Sub

Вы не можете установить целое измерение с помощью одной команды в VBA. Вам нужно перебрать его по элементам.

Black cat 22.03.2024 08:19

Чего вы хотите достичь? Попробуйте ReDim fileArray(1 To 4).

MGonet 22.03.2024 09:12

@Blackcat, я пытаюсь пройти через это, используя подпрограмму AssignVal, но это тоже не работает

Sunny Pagdiwala 22.03.2024 10:10

@MGonet, я пытаюсь прочитать 4 столбца данных, пропуская строку заголовка. Следовательно, утверждение Redim fileArray (1 to 4, 1 to lastRow-1)

Sunny Pagdiwala 22.03.2024 10:11

И что будет дальше? У вас может быть массив массивов, но вы не можете сразу заполнять отдельные столбцы при объявлении 2D-массива.

MGonet 22.03.2024 10:24

Попробуйте перейти на Set inputVar(index,i) = inputRange(i, 1).value

Black cat 22.03.2024 10:25

@MGonet, затем я буду считать первичный ключ в masterArray(1), а затем переупорядочить последние 3 столбца, используя 2 цикла for ``` for i = 1 на masterLastRow-1 for j = 1 на fileLastRow-1 if masterArray(1 ,i) = fileArray (1,j) then masterArray(2,i) = fileArray (2,j) ' то же самое для 3 и 4, выход для конца, если следующий следующий

Sunny Pagdiwala 22.03.2024 10:56

Вы использовали вкладку Excel. Почему вы не импортируете файл в Excel в формате CSV, а затем за один раз получаете диапазон из итогового листа.

freeflow 22.03.2024 10:56

Спасибо @Blackcat. Я просто вернулся, чтобы сказать, что это проблема. Я также ссылался на словарь в своем коде, и мой мозг просто объединил и то, и другое. Я нашел способ использовать AssignVal и Flatten для решения этой проблемы на случай, если у кого-то возникнет такая же проблема. Я все равно оставлю этот вопрос открытым, на случай, если у кого-то будет лучший ответ.

Sunny Pagdiwala 22.03.2024 11:04

@freeflow, файл не является CSV-файлом. Кроме того, в этом случае конечный результат все равно будет тем же объектом диапазона, которым мне нужно манипулировать с помощью массивов.

Sunny Pagdiwala 22.03.2024 11:13
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
10
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

В вашем решении функция Flatten не нужна. Вам нужно только немного переопределить AssignVal.

Public Sub AssignVal(ByRef inputVar() As Variant, ByVal index As Integer, ByVal inputRange As Range)
    'Adapted from code found at https://stackoverflow.com/questions/37689847/creating-an-array-from-a-range-in-vba
    Dim i As Long
    If UBound(inputVar, 2) = inputRange.Rows.Count Then
        For i = 1 To inputRange.Rows.Count
            inputVar(index, i) = inputRange(i, 1).Value 'loop over a range "row"
        Next i
    End If
End Sub

Но все же вы можете избежать даже этого цикла, если примете двухуровневую структуру вашего массива. Вот пример.

Sub TestArray()
   Dim fileArray()
   ReDim fileArray(1 To 2)
   Dim sheet As Worksheet
   Set sheet = ActiveSheet
   Const fileKeyColumn1 = 5
   Const fileKeyColumn2 = 8
   Const fileLastRow = 10
   fileArray(1) = sheet.Range(sheet.Cells(2, fileKeyColumn1), sheet.Cells(fileLastRow, fileKeyColumn1)).Value
   fileArray(2) = sheet.Range(sheet.Cells(2, fileKeyColumn2), sheet.Cells(fileLastRow, fileKeyColumn2)).Value
   Debug.Print fileArray(1)(3, 1)
   Debug.Print fileArray(2)(5, 1)
End Sub

Я получаю сообщение об ошибке несоответствия типов при попытке выполнить итерацию, используя приведенную выше логику. If masterArray(1)(i, 1) = fileArray(1)(j, 1) Then masterArray(2)(i, 1) = fileArray(2)(j, 1) Приведенное выше условие If выполняется, но при копировании значения выдается ошибка. Есть предположения?

Sunny Pagdiwala 22.03.2024 12:29

Только что понял, что masterArray(2), (3) и (4) просто пусты. Есть ли способ инициализировать их размерами masterArray (1)?

Sunny Pagdiwala 22.03.2024 12:40
Dim MasterArray(): MasterArray = fileArray
MGonet 22.03.2024 13:08

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