How to initialize an array of structs in MATLAB?

Matlab

Matlab Problem Overview


How can I preallocate an array of structs in MATLAB? I want to preallocate "a" in this example so that it does not resize several times.

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

Matlab Solutions


Solution 1 - Matlab

Using repmat is by far the most efficient way to preallocate structs :

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

This is ~10x faster using Matlab 2011a than preallocating via indexing, as in

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

The indexing method is only marginally faster than not preallocating.

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


Code below in case you want to verify.

        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)])

Results in command window:

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

P.S. I'd be interested to know why this is true, if anyone can explain it.

Solution 2 - Matlab

There's a nice discussion about this in Loren on the Art of MATLAB blog.

If I understand you correctly, here's a ways to initialize the struct you want:

a(100).x = 100;

With this method, we can see that elements are filled in with empty arrays.

Solution 3 - Matlab

There's a bunch of ways you can initialize a structure. For example, you can use the struct command:

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

which sets all fields x to empty.

You can also use deal to create and fill the structure if you know what data should go in there

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

Or you can use struct again (note that if a field of the structure should be a cell array, the cell needs to be enclosed in curly brackets!)

a = struct('x',xx)

Solution 4 - Matlab

The way this is supposed to be done, and the simplest is

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

If you fix the missing "tic" and add this method to the benchmarking code presented by jerad, the method I propose above is a bit slower than repmat but much simpler to implement, here is the output:

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

The reason that repmat is faster is because a value to each 'x' field is assigned during the pre-allocation, instead of leaving it empty. If the above pre-allocation technique is changed so we start with all the x fields with a value (one) assigned, like this:

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

Then, the benchmarking improves a lot, been very close or some time faster than repmat. The difference is so small that every time I run it it changes which one is faster. Here an output example:

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

Conversely, if the repmat pre-allocation is changed to set the field empty, like this

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

All the speed advantage is lost

Solution 5 - Matlab

using cell2struct is by far the fastest method I could figure out. Just check the following code to make a comparison:

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

Typical results show a mean speedup around 19 times! wrt repmat method:

cell2struct preallocation: 1.4636e-05
repmat preallocation     : 0.00028794
speedup                  : 19 X

Solution 6 - Matlab

According to this answer, there's also another way to do it:

[a.x] = deal(val);

where val is the value you want to assign to every element of the struct.

The effect of this command is different from those of the others, as every x field of every structure a will be assigned the val value.

Solution 7 - Matlab

Instead of pre-allocating the array of structs it may be easier to reverse the loop. In this way the array is allocated in the first iteration and the rest of the iterations are used to fill the structs.

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMohammad MoghimiView Question on Stackoverflow
Solution 1 - MatlabjeradView Answer on Stackoverflow
Solution 2 - MatlabblaView Answer on Stackoverflow
Solution 3 - MatlabJonasView Answer on Stackoverflow
Solution 4 - MatlabCamilo RadaView Answer on Stackoverflow
Solution 5 - MatlabAmir EkramiView Answer on Stackoverflow
Solution 6 - MatlabAlessandro CuttinView Answer on Stackoverflow
Solution 7 - MatlabJasper UijlingsView Answer on Stackoverflow