I have to load some data in a structure.
I do it inside a function.
assuming that my structure is called
loaddata
and the data are in
loaddata.corrected_data
how can I access to it within a function?
function loaddata_struct(path,namestruct)
loaddata = load(path);
data = loaddata.corrected_data; % this should change depending on the argument of the function (namestruct in this case)
end
how can I pass the name of the structure? in this case corrected_data...
You can use dynamic field names like so:
fieldOfInterest = 'corrected_data';
data = loaddata.(fieldOfInterest);
If you're loading from file, you can also access the data directly
data = load('theDataFile.mat','-mat',fieldOfInterest)
The following code will return the structure's field with the name passed to loaddata_struct function:
function data = loaddata_struct(path,namestruct)
loaddata = load(path);
data = loaddata.(namestruct);
end
Use getfield and if you need to work on a 1 x N sized struct array -
function loaddata_struct(path,fname)
loaddata = load(path);
for k1 = 1:numel(loaddata)
data{k1} = getfield(loaddata(k1),fname);
end
return;
Thus, you can use it like this - loaddata_struct(path,'corrected_data')
Do it as text and use isfield and eval. Isfield will check if the string is a field of the struct, and if it is, then use eval to evaluate loaddata.fieldname. Using isfield you make sure you never get an error, and you can do things in the else, like finding the data that has the most similar name to the one inserted, for example.
function loaddata_struct(path,fieldname)
loaddata = load(path);
if isfield(loaddata ,fieldname)
data = eval(strcat('loaddata.',fieldname));
else
error('Heeey mate, thats not a field')
end
end
Related
I have an object called TestData() that handles data processing and places it in a file in a specified format. One of the properties is data, which is stored as an array of type double. Here is the object and its constructor:
classdef TestData
properties
metaData = []; % stores meta data in Nx2 array
data = []; % stores data in PxQ array
colLabels = []; % labels columns
colUnits = []; % provides units
metaPrint % used to print metaData
temp % debugging purposes only
end
methods
%****************************************************************************%
%Function: TestData
%Purpose: Constructor used to allocate data arrays
%****************************************************************************%
function this = TestData() %constructor
this.metaPrint = [];
this.temp = [];
end %TestData()
The data that is placed into the object comes from a .m file external to the object, like so:
myTestData=TestData; % Generate an instance of the object
% Data
ErrorLine1 = zeros([length(ErrorLine')+2 1]); % Empty Vector to store 11X1
ErrorLine data
ErrorLine1(2:end-1) = ErrorLine(1:end);
mat = [Avec' Bvec' Invec' Ovec' ErrorLine1 PercentErrorOD'];
myTestData.data = mat;
So, when I set myTestData.data = mat this places the data in the object, but then calls the getter and setter functions for that object. One of the principle reasons for using these functions is to filter the data and determine if it is the correct type of data (in this case, the format would need to be double). When I try this in the code, however, it doesn't seem to work. Here is what I have written for the getter:
function data = get.data(this)
data = this.data;
end %getData
And the setter:
function this = set.data(this, data)
i = arrayfun(#(n)strcmp(class(this.data(n)), 'doube'), 1:numel(this.data)); %#ok<STISA>
disp(i)
if any(i == 0)
disp("WE HAVE A ZERO")
msg = "Data in object's 'data' property is not of type double";
error(msg);
else
this.data = data;
disp('Hi from setter')
end
end % set.data
If I run the strcmp and any functionality through the command window it works! When I run it from the editor, though, it always displays the "Hi from setter" string, even if I change "double" in the compare to "string." So, I am just not sure why it is not entering the if statement.
If there is anything that you can see in my code that could be modified to make it more efficient please let me know. Also, if there is anything else I can do my best. Thanks in advance!
In your setter, you have this line:
i = arrayfun(#(n)strcmp(class(this.data(n)), 'doube'), 1:numel(this.data));
But note that here you have not yet done this.data = data. When you test this.data, you test the old value of the property, not the value you want to assign. You need to test data.
Instead of using strcmp on the result of class, you can better test with isa. Furthermore, unless data is a cell array or a struct array, each of the elements will always be of the same class. You don't need to iterate over the whole array to test its type, just look at the type of the array itself. In the case of the cell array and the struct array, the indexing has to be different to extract elements. So, data(n) will always have the same type as data. Thus your setter can be written as:
function this = set.data(this, data)
if ~isa(data,'double')
error('WRONG!')
end
this.data = data;
end
Another issue with the code: if any(i == 0). any collapses one dimension of the input array. So if i is a 2D matrix, then the output is a row vector. Each element will be true if any of the elements in the given column is true. The if statement is only true if all elements of the given expression are nonzero. That means that all columns must have at least one 0 value for this expression to trigger.
Instead, do if any(i(:)==0). Here we make i into a column vector (this doesn't copy data, it's efficient), and thus any will return a single (scalar) value. If you have MATLAB R2018b, then you also do if any(i,'all'), which is equivalent.
You'll often see code doing if any(any(i==0)), but this fails if i happens to have three or more dimensions. It is also inefficient, the forms above are better.
I need to pass a part of a structure's name into a function.
Examples of a available structs:
systems.system1.stats.equityCurve.relative.exFee
systems.system1.stats.equityCurve.relative.inFee
systems.system2.stats.equityCurve.relative.exFee
systems.system2.stats.equityCurve.relative.inFee
systems.system1.returns.aggregated.exFee
systems.system1.returns.aggregated.inFee
systems.system2.returns.aggregated.exFee
systems.system2.returns.aggregated.inFee
... This goes on...
Within a function, I loop through the structure as follows:
function mat = test(fNames)
feeString = {'exFee', 'inFee'};
sysNames = {'system1', 'system2'};
for n = 1 : 2
mat{n} = systems.(sysNames{n}).stats.equityCurve.relative.(feeString{n});
end
end
What I like to handle in a flexible way within the loop is the middle part, i.e. the part after systems.(sysNames{n}) and before .(feeString{n}) (compare examples).
I am now looking for a way to pass the middle part as an input argument fNames into the function. The loop should than contain something like
mat{n} = systems.(sysNames{n}).(fName).(feeString{n});
How about using a helper function such as
function rec_stru = recSA(stru, field_names)
if numel(field_names) == 1
rec_stru = stru.(field_names{1});
else
rec_stru = recSA(stru.(field_names{1}), field_names(2:end));
end
This function takes the intermediate field names as a cell array.
This would turn this statement:
mat{n} = systems.(sysNames{n}).stats.equityCurve.relative.(feeString{n});
into
mat{n} = recSA(systems.(sysNames{n}), {'stats', 'equityCurve', 'relative', feeString{n}});
The first part of the cell array could then be passed as an argument to the function.
This is one of those cases where matlab is a bit unhelpful in the documentation. There is a way to use the fieldnames function in matlab to get the list of all the fields and iterate over that using dynamic fields.
systems.system1.stats.equityCurve.relative.exFee='T'
systems.system1.stats.equityCurve.relative.inFee='E'
systems.system2.stats.equityCurve.relative.exFee='S'
systems.system2.stats.equityCurve.relative.inFee='T'
systems.system1.returns.aggregated.exFee='D'
systems.system1.returns.aggregated.inFee='A'
systems.system2.returns.aggregated.exFee='T'
systems.system2.returns.aggregated.inFee='A'
dynamicvariable=fieldnames(systems.system1)
This will return a cell matrix of the field names which you can use to iterate over.
systems.system1.(dynamicvariable{1})
ans =
equityCurve: [1x1 struct]
Ideally you would have your data structure fixed in such a way that you know how many levels of depth are in your data structure.
I'm trying to automate a process for getting information out of an array of structs.
I have the following code:
function [data] = extractData(struct,str)
data = {};
for i = 1:length(struct)
data{i} = struct(i).str;
end
The problem is that I want to provide the str value referring to a pre-determined field. In it's current form, it won't accept str and say "str is an unknown field."
The easiest way to do this would to use:
function data = extractData(struct)
str = fieldnames(struct);
data = {};
for i = 1:numel(str)
data{i} = struct.(str{i});
end
end
You may also want to consider a few different things here. First, you may want to change the name of your struct to a different name as was said above. Also you might want to look into cell arrays. Cell arrays can hold variables of different types and lengths and are easier you use.
How can i access the following structure path with dynamic fieldnames:
var = 'refxtree.CaseDefinition.FlowSheetObjects.MaterialStreamObjects{8}.MaterialStreamObjectParams.Pressure.Value.Text';
fields = textscan(var,'%s','Delimiter','.');
refxtree.(fields{:}) does not work because MaterialStreamObjects contains a cell array of which I want to access the 8th cell and then continue down the structure path.
In the end I want to get and set the fieldvalues.
You need to build the appropriate input to subsref, possibly using substruct. Look at the MATLAB help.
You can define an anonymous function to navigate this particular kind of structure of the form top.field1.field2.field3{item}.field4.field5.field6.field7 (as an aside: is it really necessary to have such a complicated structure?).
getField = #(top,fields,item)top.(fields{1}).(fields{2}).(fields{3}){item}.(fields{4}).(fields{5}).(fields{6}).(fields{7})
setField = #(top,fields,item,val)subsasgn(top.(fields{1}).(fields{2}).(fields{3}){item}.(fields{4}).(fields{5}).(fields{6}),struct('type','.','subs',fields{7}),val);
You use the functions by calling
fieldValue = getField(refxtree,fields,8);
setField(refxtree,fields,8,newFieldValue);
Note that fields is required to have seven elements. If you want to generalize the above, you will have to dynamically create the above functions
In this case, it is easier to just use EVAL:
str = 'refxtree.CaseDefinition.FlowSheetObjects.MaterialStreamObjects{8}.MaterialStreamObjectParams.Pressure.Value.Text';
%# get
x = eval(str)
%# set
evalc([str ' = 99']);
Due to legacy function calls I'm sometimes forced to write ugly wrappers like this
function return = someWrapper(someField)
a = someField.a;
b = someField.b;
% and so on, realistically it's more like ten variables that
% could actually be grouped in a struct
save('params.mat', 'a', 'b'); %etc.
% then, on another machine, a function loads params.mat, does the calculations
% and saves the result in result.mat containing the variables c,d,...
load('result.mat', 'c', 'd');
return.c = c;
return.d = d;
% again, it's more than just two return values
So the basic idea is to create variables with the same names as someField's fieldnames, run a function and create a return structure using someFunction's return variable's names as fieldnames.
Is there some way simplify this using some loop e.g. over fieldnames(someField)?
Or should I actually use some different approach? Since some further processing is done with someField and result I'd like to keep using structs, but maybe a second question would be
Can save and load redirect varibale names? I.e. could e.g. the variable a in params.mat be stored using someField.a as value instead of having to assign a = someField.a first?
Why not something like this?
if this is s:
s.a=1
s.b=2
s.c=3
Then this command creates a matfile named "arguments" with variables a, b, c:
save arguments.mat -struct s
And this command loads a matfiles variables into a structure
r = load('arguments.mat')
How about using ASSIGNIN and dynamic fieldnames to loop over the structure fields and create the appropriate variables in the workspace:
function struct2base(s)
for f = fieldnames(s)'
assignin('base', f{:}, s.(f{:}))
end
Have a look at the deal() function.