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

 Respuesta aceptada

Jan
Jan el 9 de Nov. de 2014
Editada: Jan el 9 de Nov. de 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 comentario

dpb
dpb el 10 de Nov. de 2014
Editada: dpb el 11 de Nov. de 2014
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.

Iniciar sesión para comentar.

Más respuestas (1)

Kelly Kearney
Kelly Kearney el 10 de Nov. de 2014
Editada: Kelly Kearney el 10 de Nov. de 2014
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 comentarios

dpb
dpb el 11 de Nov. de 2014
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.
dpb
dpb el 11 de Nov. de 2014
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... :)

Iniciar sesión para comentar.

Categorías

Productos

Preguntada:

dpb
el 9 de Nov. de 2014

Comentada:

dpb
el 11 de Nov. de 2014

Community Treasure Hunt

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

Start Hunting!

Translated by