Syntax other than evil eval to build dynamic dataset?

Have a series of Excel spreadsheets (income/expense for an organization with which I'm involved). Have built a script logic that will find the sections for each sheet with a series of loops
% read income, expense section by fund grouping
in1=1; in2=1;
for incexp={'Income' 'Expenses'}
for grp={'Undesignated' 'Designated' 'Restricted'}
in1=in1+find(~cellfun(@isempty,strfind(t(in1+1:end,1),char(grp))),1);
in2=in2+find(strcmp((t(in2+1:end,3)), ...
['Total ' char(grp) ' ' char(incexp)])); % Section end
% get fund block within group
i1=in1+1;
if strcmp(incexp,'Income')
i2=i1+find(strcmp((t(i1+1:in2,3)), ...
['Total ' char(grp) ' Contributions'])); % Funds block
else
i2=in2;
end
% eliminate variable number of blank lines between last and total
i2=find(~cellfun(@isempty,(t(i1:i2-1,3))),1,'last')+i1-1;
end
% read various values for group, put into dataset here...
....
end
At the point of the last comment and ellipses above it would be convenient to be able to use the variable incexp as the dataset name. As the question title poses, is it possible without the use of eval? As per the usual for it, got into a passle of trouble trying to write the string. Dynamic fields for structures is similar idea which works but afaik there's not an equivalent to pick/set the structure name?
(incexp).(grp).Fund=t(in1:in2,3); % ideal (but illegal) reference

 Accepted Answer

Jan
Jan on 9 Nov 2014
Edited: Jan on 9 Nov 2014
You know, that eval is evil, because it creates variables dynamically. Then you do not need a replacement for eval, but for the dynamic creation of variables.
Use a struct instead:
Data.(incexp).(grp).Fund = t(in1:in2,3);
This is clean, save and fast. After the loops you could add this, if it is really required:
Income = Data.Income;
Expenses = Data.Expenses;

1 Comment

Well, it would surely be convenient and more generic to build the exact same thing from the data within the file instead of by hand which was the whole point of raising the question.
Sometimes, indeed, it is desired and a good idea to build a variable dynamically.
What I wanted isn't just a structure but was planning on using a dataset instead but the same thing applies. Why is it any worse to build income and expense structures dynamically than manually?
Using data for both adds another level of addressing to get to the data that's more trouble in use.
ADDENDUM
That is, this isn't the case of the usual use of eval to build variables such as A1, A2, ..., AN for N often a large number. That kind of usage is where the "evil" nature of eval raises its head and leads to headaches down the road.
Building a generic tool to process a given class of an input file that isn't dependent upon outside data to build a meaningful set of either structure or dataset names of a limited number but directly related to the data itself seems to me to be the point of writing generic procedures instead of specific ones with hardcoded variables requiring code modifications to utilize for different data input files.
Now, granted, one can confound the two sets of data here into one and then have to refer to another level of referencing but that's also not exactly looking at the data as how it's likely to be wanted most of the time.
I'm still thinking over the actual implementation/structure; further thoughts, if any, welcomed.
ADDENDUM 2
Well, it's not quite ideal in my view but it is workable it appears.
Seems like there's a wart in the dynamic structure name implementation, however, in that it doesn't take cell strings without an explicit cast to char()--that's inconvenient and don't see a reason why.
That is in the above loops
for incexp={'Income' 'Expenses'}
for grp={'Undesignated' 'Designated' 'Restricted'}
...
Data.(incexp).(grp).Fund = t(in1:in2,3);
croaks without either
Data.(char(incexp)).(char(grp)).Fund = t(in1:in2,3);
or the equivalent just a little shorter but still ugly and extra typing and something to forget to do--
Data.(incexp{:}).(grp{:}).Fund = t(in1:in2,3);
Now have to deal with merging the subsequent years where the sizes of the arrays (number of funds) grows but thought would at least acknowledge the response.

Sign in to comment.

More Answers (1)

It's not ideal (since it can confuse the interpreter), but I've occasionally used load/save to accomplish this.
Tmp.(incexp).(grp).Fund=t(in1:in2,3);
save tempfile -struct Tmp;
clear Tmp;
load tempfile;

2 Comments

Yeah, that's a workaround...
I'll continue to puzzle a while and then decide what to do.
I do need to go ahead and get this done so may just take Jan's solution and rename the two structures to the specific name even though it's somewhat defeating of the idea of writing the whole thing generically.
Gave you a vote but decided to go with the combined structure for the time being albeit I don't like it as well as might... :)

Sign in to comment.

Products

Asked:

dpb
on 9 Nov 2014

Commented:

dpb
on 11 Nov 2014

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!