Как я могу предварительно выделить нечисловой вектор в MATLAB? - PullRequest
5 голосов
/ 26 февраля 2009

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

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 ]

5 голосов
/ 26 февраля 2009

В дополнение к ответу Азима , другой способ сделать это - использовать 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 раз.

3 голосов
/ 02 марта 2009

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

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

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

3 голосов
/ 26 февраля 2009

Поскольку вы знаете поля структуры 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...