У меня есть код VBA, который проходит через набор данных и в зависимости от определенных параметров сохраняет элементы этих данных в 1 из 4 общедоступных трехмерных массивов (поскольку данные из массивов вызываются позже из другой функции). Структура массивов одинакова (как и в одинаковом количестве измерений), но размер каждого третьего измерения каждого массива различается, поэтому каждый из них Redim'd до полного размера, а затем данные добавляются процедурно. Разный размер третьего измерения является причиной использования четырех отдельных массивов, поскольку позже я также вывожу информацию о массиве в виде сводки на лист.
Код проходит через ifs и selects, а затем добавляет данные в массив в отдельной функции.
Я также хочу определить, в какой массив отправляются данные, на основе зацикленных данных, и использовать переменную для хранения имени массива, передавая его функции, которая фактически хранит данные.
Что-то вроде этого псевдокода:
Public Arr1(), Arr2(), Arr3(), Arr4()
Sub ProcessData()
Dim WhichArray, Dim1, Dim2, Dim3 'Also tried WhichArray as Variant
For Each datum in Data
'Ifs and Selects, etc to determine what array the data belongs to and to Redim each array to accommodate.
'e.g. datum belongs in Arr3(3, 1, 2)
WhichArray = Arr3 ' Also tried Set WhichArray = Arr3 here too.
Dim1 = 3
Dim2 = 1
Dim3 = 2
Call fnAddToArray(WhichArray, 3, 1, 2, datum) 'I've tried "ByRef WhichArray As Variant" here too
Next datum
End Sub
Затем я хочу вызвать сабвуфер:
Sub fnAddToArray(VarArray, Dim1, Dim2, Dim3, Datum)
VarArray(Dim1,Dim2,Dim3) = Datum
End Sub
Поскольку данных так много, и они могут попасть в любой из этих четырех массивов, я хочу иметь возможность передавать имя массива в качестве переменной в Sub, но это просто генерирует новый массив с именем VarArray и сохраняет его там вместо используя Arr3, хранящийся в переменной.
Я также попробовал зубчатый массив для хранения массивов, затем просто передал индекс в подпрограмму и сохранил значение во внутреннем массиве, как я видел это в другом месте на SO:
Public DataArrays()
DataArrays = Array(Arr1, Arr2, Arr3, Arr4)
...'same For loop as before, datum belongs in Arr3(3, 1, 2)
WhichArray = 2 '(0 base array)
Dim1 = 3
Dim2 = 1
Dim3 = 2
Call fnAddToArray(WhichArray, Dim1, Dim2, Dim3)
Next datum
End Sub
С сабом:
Sub fnAddToArray(ArrInd, Dim1, Dim2, Dim3, Datum)
DataArrays(ArrInd)(Dim1, Dim2, Dim3) = Datum
End Sub
Это просто возвращает ошибки несоответствия типов во время выполнения, даже объявляя их как варианты.
Возможно ли то, что я хочу сделать? Если да, то что я здесь делаю не так?
===================РЕДАКТИРОВАНИЕ после ответа Тима================
Это ближе к моему реальному коду, на случай, если я пропустил что-то важное:
Public arrAZVATSummData(), arrEBSummData(), arrWSSummData(), arrAZWSSummData() 'Arrays to store the summarised data for output
Public arrSummDatas(1 To 4)
Sub ProcessData()
arrSummDatas(1) = Array(arrAZVATSummData)
arrSummDatas(2) = Array(arrEBSummData)
arrSummDatas(3) = Array(arrWSSummData)
arrSummDatas(4) = Array(arrAZWSSummData)
Call fnProcessAZVAT 'AZVAT data has a different structure, stored in arrSummDatas(1)
Call fnProcessWS 'WS data contains EB, WS and AZWS data, stored in arrSummDatas(2),(3) or (4) and is the reason I want to do this this way if possible.
'Do more stuff, output a summary, etc.
End Sub
Sub fnProcessAZVAT()
Dim SummArrayNo As Long
Dim D3size, D1, D2, D3, Value
SummArrayNo = 1 'I want all data to go to arrAZVATSummData, for this sub
'...Code to determine 3rd dimension size
ReDim Preserve arrAZVATSummData(12, 3, D3Size) 'Can I do Redim Preserve arrSummDatas(SummArrayNo)(12, 3, D3size) here?
'I also think Preserve isn't necessary as no data has yet been passed to the array?
'...For Loop to process data, result:
D1 = 2
D2 = 1
D3 = 3
Value = 18.99
Call AddToDataSummArray(SummArrayNo, D1, D2, D3, Value)
'Next item
End Sub
Sub fnProcessWS()
Dim SummArrayNo As Long
Dim D3Size, D1, D2, D3, Value
'...Code to determine 3rd dimension size (same for all 3 child arrays)
ReDim Preserve arrEBSummData(12, 3, D3Size)
ReDim Preserve arrWSSummData(12, 3, D3Size)
ReDim Preserve arrAZWSSummData(12, 3, D3Size)
'...For Loop to process data, result:
SummArrayNo = 2 'this value belongs in EB, determined by loop.
D1 = 11
D2 = 0
D3 = 5
Value = 29.99
Call AddToDataSummArray(SummArrayNo, D1, D2, D3, Value)
'Next item
End Sub
Sub AddToDataSummArray(SummArrayNo As Long, D1, D2, D3, Value)
arrSummDatas(SummArrayNo)(D1, D2, D3) = arrSummDatas(SummArrayNo)(D1, D2, D3) + Value ' Currently throws subscript out of range error on 1st call.
End Sub
Спасибо за ваш (быстрый!) ответ. Я попробую это завтра утром и отчитаюсь. Итак, объявите, как вы это сделали, добавьте массивы, используя DataArrays = Array(Arr1,...) и передайте индекс DataArrays в функцию? Является ли DataArrays(var)(dim1, dim2, dim3) правильным подходом в fnAddToArray?
Я бы сказал, может быть, WhichArray = DataArray(determinedIndexHere)
тогда fnAddToArray WhichArray, Dim1, Dim2, Dim3
Я считаю, что в настоящее время использование Call
в VBA устарело.
Еще раз спасибо. Разве не это я пробовал в первом примере, напрямую обращаясь к конечному (внутреннему) массиву? Есть ли разница при использовании неровных массивов? Если WhichArray = DataArray(2) при передаче в fnAddToArray, это то же самое, что прямая передача WhichArray = Arr3?
Это сработало для меня:
Option Explicit
Public DataArrays(1 To 4)
Sub tester()
Dim i As Long
InitArrays 'populate the global array
fnAddToArray 2, 1, 3, 44 'update a couple of arrays stored in DataArrays
fnAddToArray 4, 1, 5, 99
'dump the updated arrays back to the sheet
For i = 1 To 4
ActiveSheet.Cells(i, 7).Resize(1, 5).Value = DataArrays(i)
Next i
End Sub
'Populate `DataArrays` with 2D arrays read from a worksheet
Sub InitArrays()
Dim i As Long
For i = 1 To 4
DataArrays(i) = ActiveSheet.Cells(i, 1).Resize(1, 5).Value
Next i
End Sub
Sub fnAddToArray(ArrInd As Long, Dim1 As Long, Dim2 As Long, Datum)
DataArrays(ArrInd)(Dim1, Dim2) = Datum
End Sub
Значения до/после на листе:
Большое спасибо. Нужно ли выводить массивы на лист для повторного считывания обратно в массив, или вы сделали это здесь просто для иллюстрации? Редактировать: Я думаю, что это был глупый вопрос!
Я получаю ошибки выхода за пределы диапазона индексов при попытке добавить «Датум» в массив. Я отредактирую свое исходное сообщение, используя свой фактический код, но мне интересно, не портит ли текущий порядок что-то: Объявить общедоступные родительские и дочерние массивы > Хранить пустые дочерние массивы в родительском массиве > Прокрутить некоторые данные, чтобы определить третье измерение размер каждого дочернего массива > изменить размер каждого дочернего массива до окончательного размера (все [12, 3, var]) > Пройти по данным и добавить фигуру в дочерний массив. Что-то не так с этим? Должен ли я изменить размер дочерних массивов ПЕРЕД добавлением к родительскому?
ОБНОВЛЯТЬ. Я изменил arrSummDatas(1) = Array(arrAZVATSummData) на arrSummDatas(1) = arrAZVATSummData, и это избавило от ошибки индекса!
ОБНОВЛЕНИЕ: значение, похоже, сохраняется нормально, но интересно, если я debug.print arrAZVATSummData(D1, D2, D3), оно будет пустым, но debug.print arrSummDatas(1)(D1, D2, D3) вернет только что сохраненное значение даже хотя arrSummDatas(1) ЭТО arrAZVATSummData. Кажется, я не могу напрямую ссылаться на дочерний массив после добавления в родительский массив.
ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ: Итак, я думал об этом неправильно. Кажется, что когда «Дочерний» массив добавляется к «родительскому» массиву (т. е. неровному), на дочерний массив больше нельзя ссылаться по его исходному имени, поэтому на него не может быть ReDim'd - отсюда и мои ошибки вне диапазона. Поскольку мне все еще нужно было изменить размеры дочерних массивов после добавления к родительскому, я использовал вспомогательные массивы в соответствии с ответом Тома здесь: stackoverflow.com/questions/54253970/…
Public DataArrays(1 To 4)
, а затем вы можете обратиться к каждому массиву по его индексу вDataArrays
.