assignment of structure field values in loop - matlab - matlab

I am trying to assign the field values of structure in loop.
Structure declaration with empty values:
result_struct = struct('a',{},'b',{},'c',{},'d',{})
I am assigning values in loop like that:
% assume a, b, c, d are variables in my workspace
% field names match with the variable names
for index=1:n
% some computation and store results in variables (a-d)
result_struct(index).a = a;
result_struct(index).b = b;
result_struct(index).c = c;
result_struct(index).d = d;
end
How can I assign the values to the fields using another loop? Like that:
for fname = fieldnames(result_struct)'
result_struct(index).fname = fname; % field names and variable names match
end

You need to use dynamic field names to assign to the struct (the leff-hand side). For the right hand side you could use eval but that is dangerous, so it's better to save your variable fname to a file and then load it back in as a struct prior to accessing fname, again using dynamic field names.
names = fieldnames(result_struct);
for k = 1:numel(names)
% Save variable to a file
save('tmp.mat', names{k});
% Load it back into a struct
tmp = load('tmp.mat', names{k});
result_struct(index).(names{k}) = tmp.(names{k});
end
Alternately, you can use the save and load to just transform the entire thing into a struct without having to loop through the fields.
fields = fieldnames(result_struct);
% Save all relevant variables to a file
save('tmp.mat', fields{:});
% Load it back into the result_struct
result_struct(index) = orderfields(load('tmp.mat'), fields);

Related

What is the best practice to recursively extract data from a nested structure in matlab?

I'm trying to exctract some data from a nested structure in a recursive manner. First, I know that this has a field (values) which repeats itself inside the nested structure. Secondly I know that the structure which has those values has only structures as fields. In the below code I've tried to acces the structure.values by searching if my current structure has a field named values. If it has, I put .values at the end of my structure name. If it doesn't have this field, I verify if all the fields are structures. If they are, it means that I will have to consider them further and to extract the values from each one. If the fields are not structures, it means that they are values and I save them into a new simplified structure. Example of fields that I want: S.values.model1.values.mission.values.(alt/list). Currently, with the below code I'm only able to get the values from one field and then I get an error and don't know how to approach further.
Code example:
clear all
clc
S=struct()
S.case='1';
S.type='A';
S.values.model1.case='2'
S.values.model1.type='C'
S.values.model1.values.mission.case='3'
S.values.model1.values.mission.type='D'
S.values.model1.values.mission.values.alt='none'
S.values.model1.values.mission.values.list=2
S.values.model1.values.mission.values.parameter=4
S.values.model1.values.phase.case='4'
S.values.model1.values.phase.type='A'
S.values.model1.values.phase.values.num='all'
S.values.model1.values.phase.values.eq=2
S.values.model1.values.phase.values.unit=4
S.values.model1.values.analysis.case='1'
S.values.model1.values.phase.type='A'
S.values.model1.values.phase.values.nump1.list='all'
S.values.model1.values.phase.values.nump1.table='four'
S.values.model1.values.phase.values.nump1.mean=0
S.values.model1.values.phase.values.nump2.list='none'
S.values.model1.values.phase.values.nump2.table='three';
S.values.model1.values.phase.values.nump2.mean=1
s=S.values.model1;
names=fieldnames(s);
nnames=numel(names);
newStruct={};
[valsi,newstructi]=extractValues(names,s,nnames,newStruct)
function [vals,newStruct]=extractValues(names,vals,nnames,newStruct)
if any(strcmp(names,'values'))
vals=vals.('values');
names=fieldnames(vals)
nnames=numel(names)
[vals,newStruct]=extractValues(names,vals,nnames,newStruct);
end
for j=1:nnames
value(j)=isstruct((vals.(names{j})));
end
if all(value)
for k=1:nnames
vals=(vals.(names{k}));
names=fieldnames(vals);
nnames=numel(names);
[vals,newStruct]=extractValues(names,vals,nnames,newStruct);
end
else
for j=1:nnames
value=(vals.(names{j}));
newStruct.(names{j})=value;
end
end
end
As it is known beforehand what fields are requested you can arrange the subsequent filed names in a cell array and use a loop to extract the value:
names = {'values', 'model1', 'values', 'mission', 'values', 'alt'};
out = S;
for name : names
out = out.(name{1});
end
So that is a loop version of using:
out = S.values.model1.values.mission.values.alt;
EDIT:
If you want to list all field names and all field values you can used these functions:
function out = names(s, p)
if isstruct(s)
out = {};
f = fieldnames(s);
for i = 1:numel(f)
s1 = s.(f{i});
p1 = [p '.' f{i}];
out = [out; names(s1, p1)];
end
else
out = {p};
end
end
function out = values(s)
if isstruct(s)
out = {};
f = fieldnames(s);
for i = 1:numel(f)
out = [out; values(s.(f{i}))];
end
else
out = {s};
end
end
Use them as:
n = names(S, 'S');
v = values(S);

Swap variable names and field names in a set of structs, so the field names become the struct names and vice versa?

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.

MATLAB: Loop through the values of a list from 'who' function

I have a long list of variables in my workspace.
First, I'm finding the potential variables I could be interested in using the who function. Next, I'd like to loop through this list to find the size of each variable, however who outputs only the name of the variables as a string.
How could I use this list to refer to the values of the variables, rather than just the name?
Thank you,
list = who('*time*')
list =
'time'
'time_1'
'time_2'
for i = 1:size(list,1);
len(i,1) = length(list(i))
end
len =
1
1
1
If you want details about the variables, you can use whos instead which will return a struct that contains (among other things) the dimensions (size) and storage size (bytes).
As far as getting the value, you could use eval but this is not recommended and you should instead consider using cell arrays or structs with dynamic field names rather than dynamic variable names.
S = whos('*time*');
for k = 1:numel(S)
disp(S(k).name)
disp(S(k).bytes)
disp(S(k).size)
% The number of elements
len(k) = prod(S(k).size);
% You CAN get the value this way (not recommended)
value = eval(S(k).name);
end
#Suever nicely explained the straightforward way to get this information. As I noted in a comment, I suggest that you take a step back, and don't generate those dynamically named variables to begin with.
You can access structs dynamically, without having to resort to the slow and unsafe eval:
timestruc.field = time;
timestruc.('field1') = time_1;
fname = 'field2';
timestruc.(fname) = time_2;
The above three assignments are all valid for a struct, and so you can address the fields of a single data struct by generating the field strings dynamically. The only constraint is that field names have to be valid variable names, so the first character of the field has to be a letter.
But here's a quick way out of the trap you got yourself into: save your workspace (well, the relevant part) in a .mat file, and read it back in. You can do this in a way that will give you a struct with fields that are exactly your variable names:
time = 1;
time_1 = 2;
time_2 = rand(4);
save('tmp.mat','time*'); % or just save('tmp.mat')
S = load('tmp.mat');
afterwards S will be a struct, each field will correspond to a variable you saved into 'tmp.mat':
>> S
S =
time: 1
time_1: 2
time_2: [4x4 double]
An example writing variables from workspace to csv files:
clear;
% Writing variables of myfile.mat to csv files
load('myfile.mat');
allvars = who;
for i=1:length(allvars)
varname = strjoin(allvars(i));
evalstr = strcat('csvwrite(', char(39), varname, '.csv', char(39), ', ', varname, ')');
eval(evalstr);
end

How to use file name to sort and count files stored in a .mat file?

dbhole.mat file contains files name like: d1h1,d1h2,d1h3,d1h4,d2h1,d2h2,d3h1,d3h2,d3h4,d3h5,d3h6.
I want to count the number of files having a name that starts with d1 then d2 ,d3 and so on in a loop.
If you mean that you want to get a list of the variables in a *.mat file that start with d1, d2, etc. You could use who and matfile to get a list of all variables. who accepts a regular expression which you can create specific to the variables you want to see.
matobj = matfile('filename.mat');
d1vars = who(matobj, '-regexp', '^d1h');
nD1 = numel(d1vars);
Or more generally in a loop
for k = 1:3
vars{k} = who(matobj, '-regexp', ['^d', num2str(k), 'h']);
% And get the number
nVars(k) = numel(vars{k});
end
If you have an older version of MATLAB, you can load the file into a struct and then check the fields of that struct for the pattern that you'd like.
data = load('filename.mat');
variables = fieldnames(data);
isd1 = variables(~cellfun(#isempty, regexp(variables, '^d1h')));
nD1 = numel(isd1);

Rename multiple fields in a MATLAB struct

I need to rename a bunch of fields in a structure by basically changing the prefix on it.
e.g.
MyStruct.your_firstfield
MyStruct.your_secondfield
MyStruct.your_thirdfield
MyStruct.your_forthfield
%etc....
to
MyStruct.my_firstfield
MyStruct.my_secondfield
MyStruct.my_thirdfield
MyStruct.my_forthfield
%etc...
without typing each one out...since there are many and may grow.
Thanks!
You can do this by dynamically generating field names for the output struct.
% Example input
MyStruct = struct('your_firstfield', 1, 'your_secondfield', 2, 'your_thirdfield', 3 );
% Get a cell array of MyStruct's field names
fields = fieldnames(MyStruct);
% Create an empty struct
temp = struct;
% Loop through and assign each field of new struct after doing string
% replacement. You may need more complicated (regexp) string replacement
% if field names are not simple prefixes
for ii = 1 : length(fields)
temp.(strrep(fields{ii}, 'your', 'my')) = MyStruct.(fields{ii});
end
% Replace original struct
MyStruct = temp;