Variable Depth Struct Field Reference
19 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
James Mulhern
el 26 de Feb. de 2020
Comentada: Walter Roberson
el 9 de Mayo de 2020
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 comentario
Mohammad Sami
el 27 de Feb. de 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.
Respuesta aceptada
Steven Lord
el 27 de Feb. de 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 comentario
Más respuestas (2)
Mohammad Sami
el 27 de Feb. de 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 comentario
David Saidman
el 8 de Mayo de 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)
Walter Roberson
el 27 de Feb. de 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.
2 comentarios
Ver también
Categorías
Más información sobre Structures en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!