2

I am looking for a way to iterate through nested structs in MATLAB, with each sub-struct containing a varying number of fields, some of which may contain further nested structs. For example, I have the following struct A:

    A.a.alpha=[2,3];
    A.a.beta=[8,9,10];
    A.a.delta.k=[5,6,7];
    A.a.delta.m=1;
    A.b.alpha=[22,32];
    A.b.beta.n=3;
    A.b.beta.o=[0,140];

Is there any way that I can automatically iterate through each of the end nodes of the struct A such that I can access A.a.alpha, A.a.beta, A.a.delta.k, A.a.delta.m, A.b.alpha, A.b.beta.n, and A.b.beta.o?

So far, I have seen nested for loops being used to access information that is a specific depth in (so accessing A.a.alpha, A.a.beta, A.b.alpha, but not A.a.delta.k, A.a.delta.m, A.b.beta.n, or A.b.beta.o), but my struct has those variable depths at which I need information access. I did consider using a "check if a sub-struct exists" method, but I can't figure out how to appropriately use that information to accomplish my goal here. Likewise, I also considered using a while loop that would stop at some A.end field but can't wrap my head around how to actually dig deeper into the variable depth sub-structs.

METCOMechE
  • 23
  • 4
  • 1
    I think you need a recursive function that goes "if input is struct -> get struct fields; iteratie trhough struct fields -> if struct fields is struct -> call self". With some else statement for when its not a struct, and tehrefore you can do whattever function you want. – Ander Biguri Jul 24 '23 at 16:19
  • I agree @Ander Biguri. That definitely seems like a feasible approach in principle and was also my first thought. It's the logistics of how I could do that automatically that escape me. I don't know how deep the deepest end node is, and even if I figured that out, I'm not sure how to set up an appropriately variable nested if statement or loop for executing that. – METCOMechE Jul 24 '23 at 16:37
  • this is why you want recursivity. If every time you find a struct in a field, you just call the function itself, it will keep going regardless of the depth. The answer you have gotten uses recursivity. – Ander Biguri Jul 24 '23 at 16:42
  • Understood now. Thank you all for your prompt help! – METCOMechE Jul 24 '23 at 18:15

1 Answers1

3

You can get the field names (or the data directly) using a recursive function, which calls itself on substructures.

Then you can use getfield() to grab data out of nested structures, for example in your demo getfield( A, 'a', 'alpha' ) would return [2,3], but we can also do

fieldSplit = {'a','alpha'};
data = getfield( A, fieldSplit{:} );

So by using a recursive function to generate all of the nested field names, we can generate fieldSplit for each subfield of your structure and pull out data at arbitrary depths.

Full demo with commented code for more details:

% Demo data
A = struct();
A.a.alpha=[2,3];
A.a.beta=[8,9,10];
A.a.delta.k=[5,6,7];
A.a.delta.m=1;
A.b.alpha=[22,32];
A.b.beta.n=3;
A.b.beta.o=[0,140];

% Get the nested field names
f = getNestedFields( A );

% Extract any data you want, or all of it
data = cell(1, numel(f));
for ii = 1:numel(f)
    % Split the field name on the dot separators
    fieldSplit = strsplit( f{ii}, '.' ); 
    % Use getfield to get nested data
    data{ii} = getfield( A, fieldSplit{:} );
end


function fields = getNestedFields( strct )
    % Get the field names of this structure
    fields = fieldnames( strct );
    % Loop over the fields
    for ii = 1:numel(fields)        
        if isstruct( strct.(fields{ii}) )
            % This is a substructure, recursively fetch fields
            % Replace this field name with subfield list
            fields{ii} = strcat( fields{ii}, '.', getNestedFields(strct.(fields{ii})) );
        else
            % This is a non-struct field. Nest the name so that when we
            % "flatten" things in a few lines we get back to a cell
            fields{ii} = fields(ii);
        end
    end
    % Flatten the names out to get all fields in one denested cell array
    fields = [fields{:}];
end

Result:

output

Wolfie
  • 27,562
  • 7
  • 28
  • 55