51

如何在 MATLAB 中预分配结构数组?我想在这个例子中预先分配“a”,这样它就不会多次调整大小。

a = []
for i = 1:100
  a(i).x = i;
end
4

7 回答 7

80

Usingrepmat是迄今为止最有效的预分配结构的方法:

N = 10000;    
b = repmat(struct('x',1), N, 1 );

使用 Matlab 2011a 比通过索引预分配快约 10 倍,如

N      = 10000;
b(N).x = 1

索引方法只比不预分配快一点。

No preallocation:            0.075524    
Preallocate Using indexing:  0.063774
Preallocate with repmat:     0.005234


如果您想验证,请使用下面的代码。

        clear;
        N = 10000;

    %1) GROWING A STRUCT
        tic;
        for ii=1:N
            a(ii).x(1)=1;    
        end
        noPreAll = toc;        

    %2)PREALLOCATING A STRUCT
        tic;
        b = repmat( struct( 'x', 1 ), N, 1 );
        for ii=1:N
            b(ii).x(1)=1;    
        end;  
        repmatBased=toc;        

    %3)Index to preallocate
        tic;
        c(N).x = 1;
        for ii=1:N
            c(ii).x(1)=1;    
        end;  
        preIndex=toc;

        disp(['No preallocation:        ' num2str(noPreAll)])            
        disp(['Preallocate Indexing:    ' num2str(preIndex)])
        disp(['Preallocate with repmat: ' num2str(repmatBased)])

命令窗口中的结果:

No preallocation:        0.075524    
Preallocate Indexing:    0.063774
Preallocate with repmat: 0.0052338
>> 

PS 我很想知道为什么这是真的,如果有人能解释的话。

于 2012-12-01T22:40:28.860 回答
11

有很多方法可以初始化结构。例如,您可以使用以下struct命令:

a(1:100) = struct('x',[]);

它将所有字段设置x为空。

deal如果您知道应该放入哪些数据,您也可以使用它来创建和填充结构

xx = num2cell(1:100);
[a(1:100).x]=deal(xx{:});
a(99).x
ans =
    99

或者您可以struct再次使用(注意,如果结构的字段应该是单元格数组,则单元格需要用大括号括起来!)

a = struct('x',xx)
于 2012-12-01T22:47:18.033 回答
11

Loren 在 MATLAB 艺术博客上对此进行了很好的讨论。

如果我理解正确,这里有一种方法来初始化你想要的结构:

a(100).x = 100;

使用这种方法,我们可以看到元素被空数组填充。

于 2012-12-01T22:12:12.820 回答
3

应该这样做的方式,最简单的是

a=struct('x',cell(1,N));

如果修复缺失的“tic”并将此方法添加到 jerad 提供的基准测试代码中,我上面提出的方法比 repmat 慢一点,但实现起来要简单得多,以下是输出:

No preallocation:        0.10137
Preallocate Indexing:    0.07615
Preallocate with repmat: 0.01458
Preallocate with struct: 0.07588

repmat 更快的原因是因为在预分配期间为每个“x”字段分配了一个值,而不是将其留空。如果更改了上述预分配技术,那么我们从所有 x 字段开始分配一个值(一),如下所示:

    a=cell(1,N);
    a(:)={1};
    d=struct('x',a);

然后,基准测试改进了很多,非常接近或比 repmat 快了一段时间。差异是如此之小,以至于每次我运行它都会改变哪个更快。这是一个输出示例:

No preallocation:        0.0962
Preallocate Indexing:    0.0745
Preallocate with repmat: 0.0259
Preallocate with struct: 0.0184

反之,如果repmat预分配改为设置字段为空,像这样

b = repmat( struct( 'x', {} ), N, 1 );

失去所有速度优势

于 2018-03-07T20:54:21.370 回答
0

使用 cell2struct 是迄今为止我能想到的最快的方法。只需检查以下代码进行比较:

clear;
N = 10000;

cel2s=0;
repm=0;

for i=1:100
a=0.0; b=0.0;

tic;
a = cell2struct(cell(1,N), {'x'}, 1 );
cel2s = cel2s + toc;

tic;
b = repmat(struct('x',1), N, 1 );
repm = repm + toc;
end

disp(['cell2struct preallocation: ', num2str(cel2s/100)]);
disp(['repmat preallocation     : ', num2str(repm/100)]);
disp(['speedup                  : ', num2str(fix( repm/cel2s ) ) , ' X']);

典型结果显示平均加速大约19 倍!wrt repmat方法:

cell2struct preallocation: 1.4636e-05
repmat preallocation     : 0.00028794
speedup                  : 19 X
于 2021-06-11T08:32:30.573 回答
-1

根据这个答案,还有另一种方法:

[a.x] = deal(val);

val您要分配给结构的每个元素的值在哪里。

此命令的效果与其他命令不同,因为x每个结构的每个字段都a将被赋值val

于 2015-06-24T16:39:47.473 回答
-1

与预先分配结构数组不同,反转循环可能更容易。这样,数组在第一次迭代中分配,其余的迭代用于填充结构。

a = []
for i = 100:-1:1
    a(i).x = i;
end
于 2015-07-13T15:51:47.263 回答