Is it possible to iterate through a MATLAB structure numerically like a vector instead of using the field names?
Simply, I am trying to do the following inside an EML block for Simulink:
S.a.type = 1;
S.a.val = 100;
S.a.somevar = 123;
S.b.type = 2;
S.b.val = 200;
S.b.somevar2 = 234;
S.c.type = 3;
S.c.val = 300;
S.c.somevar3 = 345;
for i = 1:length(s)
itemType = S(i).type;
switch itemType
case 1
val = S(i).val * S(i).somevar1;
case 2
val = S(i).val * S(i).somevar2;
case 3
val = S(i).val * S(i).somevar3;
otherwise
val = 0
end
end
disp(var);
You should be able to generate the fieldnames dynamically using sprintf using something like the following:
for i = 1:length(s)
theFieldName = sprintf('somevar%d', S(i).type);
val = S(i).val * getfield(S(i), theFieldName);
end
You need to use the field names, but you can do so dynamically. If you have a structure defined as:
s.field1 = 'foo';
s.field2 = 'bar';
Then you can access the field field1 with either
s.field1
s.('field1')
The only thing you need is the function fieldnames to dynamically get the field names such that your code example will look somewhat like
elements = fieldnames(S);
for iElement = 1:numel(elements)
element = S.(elements{iElement});
itemType = element.type;
switch itemType
case 1
val = element.val * element.somevar1;
case 2
val = element.val * element.somevar2;
case 3
val = element.val * element.somevar3;
end
end
If those are the exact field names, you should do some other things. First of all you would need to rethink your names and secondly you could use part of Matt's solution to simplify your code.
Related
I have a set of structs that all have the same field names. For example structs A, B, and C all have field names name and section. Is there a way to rearrange this organization of data so that the data goes from:
A.name = 'bb';
A.section = 199;
B.name = 'joe';
B.section = 101;
C.name = 'rob';
C.section = 33;
to this:
name =
A: 'bb'
B: 'joe'
C: 'rob'
section =
A: 199
B: 101
C: 33
The current code I have, for example, operates like this:
% ORIGINAL STRUCTS
A.name = 'bb';
A.section = 199;
B.name = 'joe';
B.section = 101;
C.name = 'rob';
C.section = 33;
% CREATE VARIABLE NAMES FOR NEW STRUCTS
oldFNames = fieldnames(A); % old field names
oldVNames{1} = varname(A); % old variable names
oldVNames{2} = varname(B);
oldVNames{3} = varname(C);
% RESTRUCTURE STRUCTS (SWITCH FIELDNAMES AND VARIABLE NAMES)
for j = 1:length(oldFNames)
for k = 1:length(oldVNames)
eval([oldFNames{j} '.' oldVNames{k} ' = ' oldVNames{k} '.' oldFNames{j}]);
end
end
function out = varname(var) % Function to get variable name
out = inputname(1);
end
I find the hack to use the varname function to be not great, and I don't know whether there is a way to make it easily adaptable to the number of variables I have. Any input on how to simplify this procedure would be great. Thanks.
It would be easier to do it all in a function, instead of just using a function to get the input variable name. Here's one solution:
function invert_struct(varargin)
varNames = arrayfun(#inputname, 1:nargin, 'UniformOutput', false); % Get input names
s = [varargin{:}]; % Combine inputs into a structure array
for f = fieldnames(s).' % Loop over fields
assignin('caller', f{:}, cell2struct({s.(f{:})}, varNames, 2));
end
end
And you would call it like so, with however many inputs you like:
invert_struct(A, B, C, ...);
The function uses assignin to create your new variables in the calling function and cell2struct to create a new structure from your field data and old variable names. Note that it also makes use of dynamic field names.
I declared some variables comprising of simple row vectors which represents input parameters for another function. Within a loop these variables should be used and the result will be assigned to a structure.
Now, my question is how to best access the content of the predefined variables. I found a solution using eval. However, I often read that the usage of eval should be avoided. Apparently it's not best practice. So, what's best practice for my problem?
varABC = [1,2,3];
varDEF = [4,5,6];
varGHI = [7,8,9];
names = {'ABC','DEF','GHI'};
result = {'result1','result2','result3'};
for i = 1 : 3
varString = strcat('var',names{i});
test.(result{i}) = sum(eval(varString));
end
I would suggest rewriting your code a little bit
names = {'ABC','DEF','GHI'};
result = {'result1','result2','result3'};
option 1
% Use struct instead of a simple variable
var.ABC = [1,2,3];
var.DEF = [4,5,6];
var.GHI = [7,8,9];
for i = 1 : 3
test.(result{i}) = sum(var.(names{i}));
end
option 2
% Use dictionary
c = containers.Map;
c('ABC') = [1,2,3];
c('DEF') = [4,5,6];
c('GHI') = [7,8,9];
for i = 1 : 3
test.(result{i}) = sum(c(names{i}));
end
I'm trying to modify my Farzeug structure from inside a gui popupmenu. I'm trying to use the assignin function.
contents = get(hObject,'Value')
Klima_Regler_GUI = evalin('base','Fahrzeug.Klima_Regler');
switch contents
case 1
Klima_Regler_GUI = 1;
assignin('base','Fahrzeug.Klima_Regler',Klima_Regler_GUI);
case 2
Klima_Regler_GUI = 0.75;
assignin('base','Fahrzeug.Klima_Regler',Klima_Regler_GUI);
case 3
Klima_Regler_GUI = 0.50;
assignin('base','Fahrzeug.Klima_Regler',Klima_Regler_GUI);
case 4
Klima_Regler_GUI= 0.25;
assignin('base','Fahrzeug.Klima_Regler',Klima_Regler_GUI);
case 5
Klima_Regler_GUI = 0;
assignin('base','Fahrzeug.Klima_Regler',Klima_Regler_GUI);
otherwise
but I keep getting this error:
I will appreciate any help
It is impossible to change the structure field using assignin because
assignin(ws, 'var', val) assigns the value val to the variable var in the workspace ws. The var input must be the array name only; it cannot contain array indices.
But you can use evalin to do this:
evalin('base',['Fahrzeug.Klima_Regler = ' num2str(Klima_Regler_GUI)])
I have a constructor like this:
function p = class_name(folder, file_name)
xmlfile = fullfile(folder, file_name);
xDoc = xmlread(xmlfile);
struct = xml2struct(xDoc);
%lots of repetitive code
end
It reads and XML file and transforms it into a struct. The struct elements are then assign to the class's properties/fields using some repetitive code like this:
if(isfield(struct.parameters, 'parameter_name'))
p.property_name = struct.parameters.parameter_name.Text;
else
p.property_name = '';
end
I would like to put this into a method/function which, given the name of the struct element (here 'parameter_name') and the name of the class field/property (here 'property_name') assigns the former to the latter.
Is it possible to write a generic function/method for this? Thanks.
You can implement such a function using dynamic field names. This is the recommended implementation for such cases:
function p = setparam(s, p, param_name, prop_name)
if(isfield(s.parameters, param_name))
param = s.parameters.(param_name);
p.(prop_name) = param.Text;
else
p.(prop_name) = '';
end
end
You can also use setfield and getfield on older versions of MATLAB:
function p = setparam(s, p, param_name, prop_name)
if(isfield(s.parameters, param_name))
param = getfield(s.parameters, param_name);
p = setfield(p, prop_name, getfield(param, 'Text'));
else
p = setfield(p, prop_name, '');
end
end
Do not use struct for structure name in your code - it is a reserved keyword.
Use dynamic field names:
yourStruct.parameters.('parameter_name')
Here is a a generic function:
Can be used for either structs or class objects
function obj_to = set_props(obj_to, obj_from)
% insert properties from obj_from into obj_to.
props_from = fieldnames(obj_from);
props_to = fieldnames(obj_to);
for k = 1 : length(props_to)
if ismember(props_to{k}, props_from)
obj_to.(props_to{k}) = obj_from.(props_to{k});
else
obj_to.(props_to{k}) = '';
end
end
Now, in the constructor:
function obj = class_name(folder, file_name)
xmlfile = fullfile(folder, file_name);
xDoc = xmlread(xmlfile);
s = xml2struct(xDoc); % do not use word "struct" for variables
set_props(obj, s); % if obj has handle, no need to return it from set_props()
end
Given a structure array, how do I rename a field? For example, given the following, how do I change "bar" to "baz".
clear
a(1).foo = 1;
a(1).bar = 'one';
a(2).foo = 2;
a(2).bar = 'two';
a(3).foo = 3;
a(3).bar = 'three';
disp(a)
What is the best method, where "best" is a balance of performance, clarity, and generality?
Expanding on this solution from Matthew, you can also use dynamic field names if the new and old field names are stored as strings:
newName = 'baz';
oldName = 'bar';
[a.(newName)] = a.(oldName);
a = rmfield(a,oldName);
Here's a way to do it with list expansion/rmfield:
[a.baz] = a.bar;
a = rmfield(a,'bar');
disp(a)
The first line was originally written [a(:).baz] = deal(a(:).bar);, but SCFrench pointed out that the deal was unnecessary.
Here's a a way to do it with struct2cell/cell2struct:
f = fieldnames(a);
f{strmatch('bar',f,'exact')} = 'baz';
c = struct2cell(a);
a = cell2struct(c,f);
disp(a)