Я работаю над конкретной проблемой, когда мне приходится читать несколько столбцов из «листа» в «файле». Эти столбцы должны временно храниться в «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
Чего вы хотите достичь? Попробуйте ReDim fileArray(1 To 4)
.
@Blackcat, я пытаюсь пройти через это, используя подпрограмму AssignVal, но это тоже не работает
@MGonet, я пытаюсь прочитать 4 столбца данных, пропуская строку заголовка. Следовательно, утверждение Redim fileArray (1 to 4, 1 to lastRow-1)
И что будет дальше? У вас может быть массив массивов, но вы не можете сразу заполнять отдельные столбцы при объявлении 2D-массива.
Попробуйте перейти на Set inputVar(index,i) = inputRange(i, 1).value
@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, выход для конца, если следующий следующий
Вы использовали вкладку Excel. Почему вы не импортируете файл в Excel в формате CSV, а затем за один раз получаете диапазон из итогового листа.
Спасибо @Blackcat. Я просто вернулся, чтобы сказать, что это проблема. Я также ссылался на словарь в своем коде, и мой мозг просто объединил и то, и другое. Я нашел способ использовать AssignVal и Flatten для решения этой проблемы на случай, если у кого-то возникнет такая же проблема. Я все равно оставлю этот вопрос открытым, на случай, если у кого-то будет лучший ответ.
@freeflow, файл не является CSV-файлом. Кроме того, в этом случае конечный результат все равно будет тем же объектом диапазона, которым мне нужно манипулировать с помощью массивов.
В вашем решении функция 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 выполняется, но при копировании значения выдается ошибка. Есть предположения?
Только что понял, что masterArray(2), (3) и (4) просто пусты. Есть ли способ инициализировать их размерами masterArray (1)?
Dim MasterArray(): MasterArray = fileArray
Вы не можете установить целое измерение с помощью одной команды в VBA. Вам нужно перебрать его по элементам.