6

Assuming I have a struct S of size 0x1 with the fields a and b, what is the most elegant way to add a field c to it?

Usually I am able to do it like this:

S = struct('a',0,'b',0); %1x1 struct with fields a,b
S.c = 0

However, if I receive an empty struct this does not work anymore:

S = struct('a',0,'b',0);
S(1) = []; % 0x1 struct with fields a,b
S.c = 0;
% A dot name structure assignment is illegal when the structure is empty.  
% Use a subscript on the structure.

I have thought of two ways to deal with this, but both are quite ugly and feel like workarounds rather than solutions. (Note the possibility of a non-empty struct should also be dealt with properly).

  1. Adding something to the struct to ensure it is not empty, adding the field, and making the struct empty again
  2. Initializing a new struct with the required fieldnames, filling it with the data from the original struct, and overwriting the original struct

I realize that it may be odd that I care about empty structs, but unfortunately part of the code that is not managed by me will crash if the fieldname does not exist. I have looked at help struct, help subsasgn and also searched for the given error message but so far I have not yet found any hints. Help is therefore much appreciated!

Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122

4 Answers4

7

You can use deal to solve this problem:

S = struct('a',0,'b',0);
S(1) = [];

[S(:).c] = deal(0);

This results in

S = 

1x0 struct array with fields:
    a
    b
    c 

This works also for non-empty structs:

S = struct('a',0,'b',0);

[S(:).c] = deal(0);

which results in

S = 

    a: 0
    b: 0
    c: 0
H.Muster
  • 9,297
  • 1
  • 35
  • 46
2

How about

S = struct('a', {}, 'b', {}, 'c', {} );

To create an empty struct?

Another way is to use mex file with mxAddField as a workaround to the error you got:

A dot name structure assignment is illegal when the structure is empty.
Use a subscript on the structure.

Shai
  • 111,146
  • 38
  • 238
  • 371
  • I guess that I could use an if statement to see if it is indeed empty and then use this, but I still hope that there is a way to do it without the check first. – Dennis Jaheruddin Feb 12 '13 at 10:35
2

You can use setfield to solve the problem.

S = struct('a', {}, 'b', {});
S = setfield(S, {}, 'c', [])

This results in

S = 

0x0 struct array with fields:
    a
    b
    c
  • Very nice, I don't see this possibility in the documentation but it seems to work the same as the accepted solution. -- Whilst looking at this, I stumbled upon one of these rare methods to crash Matlab (2012b): `S = struct(); S(:)=[]; S().e=[]; S(3,3).f=[]; S().g=[];` – Dennis Jaheruddin Jul 01 '15 at 19:02
  • 1
    This code gives me `Expected one output from a curly brace or dot indexing expression, but there were 0 results.` (R2016b). – nekomatic Oct 18 '16 at 11:43
1

Just to expand on @Shai's answer, here is a simple MEX-function you can use:

addfield.c

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    char *fieldname;

    /* Check for proper number of input and output arguments */
    if (nrhs != 2) {
        mexErrMsgIdAndTxt("struct:nrhs", "Two inputs required.");
    } else if (nlhs > 1) {
        mexErrMsgIdAndTxt("struct:nlhs", "Too many output arguments.");
    } else if (!mxIsStruct(prhs[0])) {
        mexErrMsgIdAndTxt("struct:wrongType", "First input must be a structure.");
    } else if (!mxIsChar(prhs[1]) || mxGetM(prhs[1])!=1) {
        mexErrMsgIdAndTxt("struct:wrongType", "Second input must be a string.");
    }

    /* copy structure for output */
    plhs[0] = mxDuplicateArray(prhs[0]);

    /* add field to structure */
    fieldname = mxArrayToString(prhs[1]);
    mxAddField(plhs[0], fieldname);
    mxFree(fieldname);
}

Example:

>> S = struct('a',{});
>> S = addfield(S, 'b')
S = 
0x0 struct array with fields:
    a
    b
Community
  • 1
  • 1
Amro
  • 123,847
  • 25
  • 243
  • 454
  • @down-voter: why, care to comment? If there is a problem with the code, I'm happy to improve it... It works fine on my end! – Amro Nov 03 '14 at 17:05