Как я могу предварительно выделить нечисловой вектор в MATLAB?

Я часто обнаруживал, что делаю что-то вроде этого:

unprocessedData = fetchData();  % returns a vector of structs or objects
processedData = [];             % will be full of structs or objects

for dataIdx = 1 : length(unprocessedData) 
    processedDatum = process(unprocessedData(dataIdx));
    processedData = [processedData; processedDatum];
end

Что, хотя и функционально, не оптимально - processedData вектор растет внутри петли. Четное mlint предупреждает меня, что я должен рассмотреть возможность предварительного распределения скорости.

Были данные вектора int8 Я мог бы сделать это:

% preallocate processed data array to prevent growth in loop
processedData = zeros(length(unprocessedData), 1, 'int8');

и измените цикл, чтобы заполнить векторные слоты, а не объединять.

Есть ли способ предварительно выделить вектор, чтобы впоследствии он мог содержать структуры или объекты?


Обновление: вдохновленный ответом Азима, я просто изменил порядок зацикливания. Обработка последнего элемента сначала вызывает предварительное выделение всего вектора в первом обращении, поскольку отладчик подтверждает:

unprocessedData = fetchData();

% note that processedData isn't declared outside the loop - this breaks 
% it if it'll later hold non-numeric data. Instead we exploit matlab's 
% odd scope rules which mean that processedData will outlive the loop
% inside which it is first referenced: 

for dataIdx = length(unprocessedData) : -1 : 1 
    processedData(dataIdx) = process(unprocessedData(dataIdx));
end

Это требует, чтобы любые объекты, возвращаемые process() иметь действительный конструктор с нулевым аргументом, так как MATLAB инициализирует processedData на первом пишите с реальными объектами.

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

3 ответа

Решение

Так как вы знаете поля структуры processedData и вы знаете его длину, одним из способов будет следующее:

unprocessedData = fetchData();
processedData = struct('field1', [], ...
                       'field2', []) % create the processed data struct
processedData(length(unprocessedData)) = processedData(1); % create an array with the required length
for dataIdx = 1:length(unprocessedData)
    processedData(dataIdx) = process(unprocessedData(dataIdx));
end

Это предполагает, что process функция возвращает структуру с теми же полями, что и processedData,

В дополнение к ответу Азима, другой способ сделать это - использовать repmat:

% Make a single structure element:
processedData = struct('field1',[],'field2',[]);
% Make an object:
processedData = object_constructor(...);
% Replicate data:
processedData = repmat(processedData,1,nElements);

где nElements количество элементов, которые вы будете иметь в структуре или массиве объектов.

ВНИМАНИЕ: Если объект, который вы создаете, является производным от класса дескриптора, вы не будете реплицировать сам объект, просто обрабатывать ссылки на него. В зависимости от вашей реализации вам, возможно, придется вызвать метод конструктора объекта nElements раз.

Вы можете передать массив ячеек struct соответствующего размера:

processedData = struct('field1', cell(nElements, 1), 'field2', []);

Это создаст структурный массив того же размера, что и массив ячеек.

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