Variable Depth Struct Field Reference

15 views (last 30 days)
Hello,
I would like to programmatically reference different struct fields and I traditionally do that with the .() reference.
example_struct.(fieldname(i)) = some_data;
With my current project I would like to perform a similar reference, but the specific struct variable are of different depths. For example if I have the following struct
S.a.b.c = 1;
S.a.b.d = 2;
S.a.b.e = struct('f',[3 4],'g',5);
S.h = 50
I would like to do the equivalent of the following code, but dynamically reference the sub structs.
S.a.b.c = some_val(1);
S.a.b.e.f = some_val(2);
S.h = some_val(3);
I attempted the following code and it does not work.
fields_names = {'a.b.c';'a.b.e.f';'h'};
for i = 1:3
S.(field_names{i}) = some_val(i);
end
%I also tried
fields = {'a','b','c'};
S = setfield(S,fields,some_val(1));
My question is how do I reference these fields dynamically and adjust their value inside the same loop. I could create the following function, but it is not very robust.
function S = fucntion_name(in_Struct,field_names,depth,value)
switch depth
%Other cases omitted
case 3
S = in_Struct.(field_names(1)).(field_names(2)).(field_names(3)) = value;
end
end
Is there another way? Is there a way to pass the values into setfield() similarly to how multiple function varargin inputs can be pass as a single struct input?
  1 Comment
Mohammad Sami
Mohammad Sami on 27 Feb 2020
There are two potential solutions. You can look at the function subsref in Matlab
or write a recursive function which calls itself with one less argument, and a base case.

Sign in to comment.

Accepted Answer

Steven Lord
Steven Lord on 27 Feb 2020
You were very close with your setfield call. You need to turn your list of fields into a comma-separated list so that each element of the cell array fields is passed into setfield as a separate input.
fields = {'a','b','c'};
S = setfield(S,fields{:},42) % Call setfield with 5 inputs, the equivalent of
% S = setfield(S, 'a', 'b', 'c', 42)
S_dot_a_dot_b = S.a.b
One easy way to create the cell array fields from the character vector 'a.b.c' is to use split.
fields2 = split('a.b.c', '.')
Don't worry about the orientation of fields2 being different from fields. They will generate the same comma-separated list.
  1 Comment
James Mulhern
James Mulhern on 27 Feb 2020
It was the differnece between how I called fields
S = setfield(S,fields{:},some_val) %This works
S = setfield(S,fields,some_val) %This does not work
I forgot that cell{:} return a comma seperated list. I should remember because I get errors when I attempt to address a vecotor of cell with this call.

Sign in to comment.

More Answers (2)

Mohammad Sami
Mohammad Sami on 27 Feb 2020
You can use the subsref function to index into the struct. You need to create the variable s dynamicall.
To assign you can use the subasgn function
a = struct('b',struct('c',1));
s(1).type = '.';
s(1).subs = 'b';
s(2).type = '.';
s(2).subs = 'c';
out = subsref(a,s);
a = subsasgn(a,s,2);
a.b.c % value changed to 2
For example
function S = fucntion_name(in_Struct,field_names,value)
for i = 1:length(field_names)
s(i).type = '.';
s(i).subs = field_names{i};
end
S = subsasgn(in_Struct,s,value);
end
  1 Comment
David Saidman
David Saidman on 8 May 2020
that solved a lot of my problems. i made an overloaded setfield function
can also remove the loop by doing below, but its by no means better than Mohammad's loop
n = numel(field_names);
[s(1:n).type] = deal('.');
[s(1:n).subs] = field_names{:};
S = subsasgn(in_Struct,s,value)

Sign in to comment.


Walter Roberson
Walter Roberson on 27 Feb 2020
Mohammad Sadi's approaches are fine. There is another class of approach though. You can split the string at periods, creating a cell array of character vectors. You can then use cell expansion to drop the list into a setfield call without having to special case the number of items you pass in.

Categories

Find more on Structures in Help Center and File Exchange

Products


Release

R2015b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!