Reputation: 95
I'm trying to create a structure array at runtime in Matlab.
A= {'dark';'oa_45'; 'oa_225'};
for i = 1:3
tmp =load([folder '/' A{i} '.txt']);
eval([A{i} '.count=tmp(:,1:2)']);
eval([A{i} '.mean=mean(tmp(:,1:2),1)']);
eval([A{i} '.sqrtmean=sqrt(' A{i} '.mean)']);
eval([A{i} '.stdev=std(tmp(:,1:2),1)']);
eval(A{i});
end
Since I know, that using eval
is a rather bad practice, I would like to know whether there is a simple way to avoid eval
here.
I figured it would be possible to create the structure array before the loop and then assign only the sub fields in the loop with the parenthesis notation:
s.(A{i}).count = ...
I found some suggestions here that say, it seems to be possible with subsasgn
. That seemed rather more complicated than the eval
function.
Does somebody know a simple way to avoid the eval
function, or is it just the best call here?
I'm just asking out of curiosity, I guess for these three vectors, the loss in performance doesn't really matter.
Best Regards, Mechanix
Upvotes: 4
Views: 307
Reputation: 221514
Assuming you would be okay with having a single struct that will hold the three structs named 'dark','oa_45', 'oa_225' and the field 'sqrtmean' being dropped down to the bottom, you might wanna try this -
Code Version 1 (Recommended)
A= {'dark';'oa_45'; 'oa_225'};
fieldnames1 = {'count';'mean';'stdev'};
funcnames1 = {'';'mean';'std'};
for k = 1:numel(A)
tmp =load([folder '/' A{k} '.txt']);
struct1 = A{k};
for i = 1:numel(fieldnames1)
if isempty(funcnames1{i})
comp_struct.(struct1).count=tmp(:,1:2);
else
fh = str2func(funcnames1{i});
comp_struct.(struct1).(fieldnames1{i}) = fh(tmp(:,1:2),1);
end
end
comp_struct.(struct1).sqrtmean = sqrt(comp_struct.(struct1).mean);
end
Thus, 'comp_struct.dark' would be your original 'dark' and so on.
Go one step further and remove the IF-ELSE -
Code Version 2 (Highly Recommended)
A= {'dark';'oa_45'; 'oa_225'};
fieldnames1 = {'count';'mean';'stdev'};
funcnames1 = {'donothing';'mean';'std'};
for k = 1:numel(A)
tmp =load([folder '/' A{k} '.txt']);
struct1 = A{k};
for i = 1:numel(fieldnames1)
fh = str2func(funcnames1{i});
comp_struct.(struct1).(fieldnames1{i}) = fh(tmp(:,1:2),1);
end
comp_struct.(struct1).sqrtmean = sqrt(comp_struct.(struct1).mean);
end
Don't forget to add this function in path -
function out = donothing(varargin)
out = varargin{1};
If the nested loops are bothering you or you don't want to get into function handles and you were only looking to replace EVAL with something that would occupy the same space in terms of code lines, use the the following, but I won't recommend for a general case though -
Code Version 3 (Not Recommended)
A= {'dark';'oa_45'; 'oa_225'};
for k = 1:numel(A)
tmp =load([folder '/' A{k} '.txt']);
comp_struct.(A{k}).count = tmp(:,1:2);
comp_struct.(A{k}).mean = mean(tmp(:,1:2),1);
comp_struct.(A{k}).sqrtmean = sqrt(comp_struct.(A{k}).mean);
comp_struct.(A{k}).stdev = std(tmp(:,1:2),1);
end
Upvotes: 2
Reputation: 20914
But you're not creating "a structure array", you're creating 3 separate struct variables! An actual structure array would be highly preferable:
A = {'dark';'oa_45'; 'oa_225'};
% Preallocation is obviously optional, but good practice
% A cell array initialiser will make structarray the same size
structarray = struct('name',A,'count',[],'mean',[],'sqrtmean',[],'stdev',[]);
for i = 1:length(A)
tmp = load([folder '/' A{i} '.txt']);
% structarray(i).name = A{i}; % if we didn't preallocate
structarray(i).count = tmp(:,1:2);
structarray(i).mean = mean(tmp(:,1:2),1);
structarray(i).sqrtmean = sqrt(structarray(i).mean);
structarray(i).stdev = std(tmp(:,1:2),1);
end
Avoiding eval
can often involve a fair bit of restructuring, but in almost all cases the code you end up with is more robust and easier to work with.
For example, relying on specifically named variables is fine when you start out with the command line and simple scripts in the base workspace - it makes sense for the user, to keep track of what's what. Once you progress to bigger problems you'll find it really doesn't scale well and you need to do things in a way that makes sense for the program - when you're passing data between functions the names become irrelevant anyway. That's when tools like cell arrays and struct arrays really come into their own. Structs are particularly handy since you can nearly always put in an extra field purely to identify things, as I have with name
above.
Upvotes: 0