Как я могу предварительно выделить нечисловой вектор в 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 по-прежнему жалуется на возможный рост массива, но я думаю, это потому, что он не может распознать итерацию обратного цикла ...


person Dan Vinton    schedule 26.02.2009    source источник


Ответы (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.

person Azim J    schedule 26.02.2009

Помимо ответа Азима, еще один способ сделать это - использовать _ 1_:

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

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

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

person gnovice    schedule 26.02.2009

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

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

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

person ManWithSleeve    schedule 02.03.2009
comment
+1 Это хорошая альтернатива для создания массивов структур, особенно если у вас уже есть массивы ячеек с данными, которыми вы хотите заполнить поля. - person gnovice; 02.03.2009