Работа с массивами в памяти VBA и избежание циклов с помощью векторизации

Я хорошо разбираюсь в MATLAB, но в эти дни я работаю в VBA, поскольку MATLAB менее доступен для меня, и я борюсь с попытками делать вещи в VBA (например, векторизацию), с которыми я мог бы легко справиться в MATLAB.

Допустим, у меня есть таблица данных в excel следующего вида:

record  startDate   endDate count
1   100 103 10
2   98  102 5
3   101 104 4

Я хотел бы выполнить всю свою обработку в памяти (избегая циклов), а затем вывести файл результатов, который выглядит следующим образом:

    1   2   3   Sum
98  0   5   0   5
99  0   5   0   5
100 10  5   0   15
101 10  5   4   19
102 10  5   4   19
103 10  0   4   14
104 0   0   4   4

По сути, я начинаю с самой ранней даты и перебираю последнюю дату, а затем проверяю, включена ли каждая дата в окно даты для каждой записи, и если это так, я применяю количество записей к этому дню, а затем суммирую их.

Я создал включенный вывод, используя простую функцию рабочего листа, но я хотел бы иметь возможность воспроизвести процесс в VBA, специально избегая зацикливания, по крайней мере, уменьшая до 1 цикла вместо встроенных циклов.

Если бы я был в MATLAB, я бы нашел логический массив, удовлетворяющий условию, например:

numDays = 7;
numRecords = 3;
startDate = [100; 98; 101];
endDate = [103; 102; 104];
dateVector = [98; 99; 100; 101; 102; 103; 104];
count = [10; 5; 4];
dateLogic = logical(numDays,numRecords);
for d = 1:numDays
  dateLogic(d,:) = dateVector(d) >= startDate(:,1) &  dateVector(d) <= endDate(:,1)
end
countMatrix = dateLogix * count';
Sum = sum(countMatrix,2);

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

Пожалуйста, извините за возможные синтаксические ошибки, так как сейчас у меня нет доступа к MATLAB.

Во всяком случае, как я могу сделать что-то подобное в VBA. Существует ли эквивалентная нотация двоеточия для ссылки на весь диапазон столбцов или строк в массиве. Я буду применять к большому набору данных, поэтому эффективность имеет существенное значение. Чем больше я могу сделать в памяти перед вставкой, тем лучше.

Заранее спасибо.


person Keith D    schedule 23.07.2014    source источник
comment
Вам нужно будет использовать некоторые пользовательские функции для нарезки массива. С двумерным матричным массивом довольно легко построить функцию GetRow или функцию GetColumn. Здесь также есть масса полезных вспомогательных функций: www.cpearson.com/excel/array.htm   -  person David Zemens    schedule 24.07.2014
comment
Две хорошие зацепки, хотя я хочу избежать изучения другого языка (октавы). Функции массива по предоставленной ссылке могут поддерживать то, что мне нужно.   -  person Keith D    schedule 24.07.2014


Ответы (1)


Вот одна из возможностей: попробуйте использовать образцы данных в A1:A4 новой книги.

Sub NewTable()

Set Table = Sheet1.[a2:d4]

With Application

    Record = .Transpose(.Index(Table, , 1))
    FirstDate = .Transpose(.Index(Table, , 2))
    LastDate = .Transpose(.Index(Table, , 3))
    Count = .Transpose(.Index(Table, , 4))

    Dates = .Evaluate("row(" & .Min(FirstDate) & ":" & .Max(LastDate) & ")")
    Values = .PV(, Count, .PV(, .GeStep(Dates, FirstDate), .GeStep(LastDate, Dates)))
    Sum = .MMult(Values, .Power(.Transpose(Record), 0))

End With

Sheet1.[F1].Offset(, 1).Resize(, UBound(Values, 2)) = Record
Sheet1.[F2].Resize(UBound(Dates)) = Dates
Sheet1.[G2].Resize(UBound(Values), UBound(Values, 2)) = Values
Sheet1.[G2].Offset(, UBound(Values, 2)).Resize(UBound(Dates)) = Sum

End Sub
person lori_m    schedule 04.09.2014