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

Mohammad Sami
Mohammad Sami 2020년 2월 27일
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.

댓글을 달려면 로그인하십시오.

 채택된 답변

Steven Lord
Steven Lord 2020년 2월 27일

0 개 추천

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

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.

댓글을 달려면 로그인하십시오.

추가 답변 (2개)

Mohammad Sami
Mohammad Sami 2020년 2월 27일

1 개 추천

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

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)

댓글을 달려면 로그인하십시오.

Walter Roberson
Walter Roberson 2020년 2월 27일

0 개 추천

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.

카테고리

도움말 센터File Exchange에서 Structures에 대해 자세히 알아보기

제품

릴리스

R2015b

질문:

2020년 2월 26일

댓글:

2020년 5월 9일

Community Treasure Hunt

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

Start Hunting!

Translated by