I've often found myself doing something like this:
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
Which, whilst functional, isn't optimal - the processedData
vector is growing inside the loop. Even mlint
warns me that I should consider preallocating for speed.
Were data a vector of int8
, I could do this:
% preallocate processed data array to prevent growth in loop
processedData = zeros(length(unprocessedData), 1, 'int8');
and modify the loop to fill vector slots rather than concatenate.
is there a way to preallocate a vector so that it can subsequently hold structs or objects?
Update: inspired by Azim's answer, I've simply reversed the loop order. Processing the last element first forces preallocation of the entire vector in the first hit, as the debugger confirms:
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
This requires that any objects returned by process()
have a valid zero-args constructor since MATLAB initialises processedData
on the first write to it with real objects.
mlint
still complains about possible array growth, but I think that's because it can't recognise the reversed loop iteration...
In addition to Azim's answer, another way to do this is using repmat
:
% Make a single structure element:
processedData = struct('field1',[],'field2',[]);
% Make an object:
processedData = object_constructor(...);
% Replicate data:
processedData = repmat(processedData,1,nElements);
where nElements
is the number of elements you will have in the structure or object array.
BEWARE: If the object you are making is derived from the handle class, you won't be replicating the object itself, just handle references to it. Depending on your implementation, you might have to call the object constructor method nElements
times.
Since you know the fields of the structure processedData
and you know its length, one way would be the following:
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
This assumes that the process
function returns a struct with the same fields as processedData
.
You can pass in a cell array to struct
of the appropriate size:
processedData = struct('field1', cell(nElements, 1), 'field2', []);
This will make a structure array that is the same size as the cell array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With