如何在 MATLAB 中预分配非数值向量?

发布于 2024-07-14 04:34:31 字数 1554 浏览 3 评论 0原文

我经常发现自己在做这样的事情:

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');

并修改循环以填充向量槽而不是连接。

有没有办法预先分配向量,以便它随后可以保存结构或对象?


更新: 灵感来自 Azim 的回答,我只是颠倒了循环顺序。 处理最后一个元素首先会强制在第一次命中中预分配整个向量,正如调试器所确认的:

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 仍然抱怨可能的数组增长,但我认为这是因为它无法识别反向循环迭代......

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...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

や三分注定 2024-07-21 04:34:31

除了Azim的回答之外,另一种方法是使用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 次。

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.

千里故人稀 2024-07-21 04:34:31

由于您知道结构体 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 函数返回一个与以下字段具有相同字段的结构体: 已处理数据

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.

我也只是我 2024-07-21 04:34:31

您可以将元胞数组传递给适当大小的 struct :

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

这将创建一个与元胞数组大小相同的结构体数组。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文