Alternative to Eval for small number of variables

7 views (last 30 days)
Hello
I have been reading about using (or not using) eval, but have a situation where I cannot figure out how to get around it. I am hoping that someone can help me.
I have a program that checks some values based on an external .csv file.
I have variables already set that are associated with a value, eg
var1 = 50
var2 = 500
...
The .csv file lists the variable names in col 1, and has the numeric value to check in col 2 -
{'var1'} {[val1]}
{'var2'} {[val2]}
{'var3'} {[val3]}
... .....
{'varN'} {[valN]}
The specific var names and values may change value and order, so the .csv file could look like this:
{'var3'} {[val3]}
{'var2'} {[val2]}
{'var1'} {[val1]}
... .....
{'varN'} {[valN]}
I am reading in the file using readcell:
F = readcell('filename.csv');
var_names = F(:,1);
var_values = cell2mat(F(:,2));
As noted, the order of entries into the .csv file may change, so I can't code something like:
if var1 > var_values(1)
% something
end
because sometimes var2 and its associated value may be in the first row etc, or var1 might be in row 3 etc
I get what I want using
for i = 1:length(var_names)
if eval(var_names{i}) > var_values(i)
% something
end
end
but I want to do this in a way that doesn't use eval. Any help would be appreciated.
thanks!
------------------------------------------------------------------------
ADDENDUM:
I have attached a csv file as suggested.
F = readcell('filename.csv');
var_names = F(:,1)
var_names = 4×1 cell array
{'a'} {'b'} {'c'} {'d'}
var_values = cell2mat(F(:,2))
var_values = 4×1
5 10 15 20
a = 10;
b = 15;
c = 1;
d = 20;
e = 25;
To attempt to clarify: The issue I have is that I dont know what variable names are going to be in the .csv file ahead of time. So I don't think I can use ismember() or strcmp()
Lets say I want to check if the variable listed in the first column of the csv file (var_names) has a value assigned that is > than the value in the csv column 2 (var_values). However, I don't know before hand which of the possible variables will be in the csv file. So I don't see how I can use strmp() or ismember() without coding all possibilities.
So for example lets say that the first line in the csv file is 'a' and '5' (as it is in the attached file). I therefore want to check that workspace variable a (which was assigned a value of 10 above) is > 5 (value in the csv corresponding to the row with var_name = 'a') and store the answer (1 or 0) in variable N:
I could do it using eval:
for i = 1:length(var_names);
N = eval(var_names{i}) > var_values(i)
end
N = logical
1
N = logical
1
N = logical
0
N = logical
0
or as suggested using strcmp:
for i = 1:length(var_names);
if strcmp(var_names{i}, 'a')
N = a > var_values(i)
end
end
N = logical
1
for i = 1:length(var_names);
if strcmp(var_names{i}, 'b')
N = b > var_values(i)
end
end
N = logical
1
for i = 1:length(var_names);
if strcmp(var_names{i}, 'c')
N = c > var_values(i)
end
end
N = logical
0
etc etc
but the issue is that maybe the csv file only contains a few out of many posisble variables.....I wanted to avoid having to code all possibilities. Even if I put the varaibles names in a vector I still seem to run into the same issue when assigning a value to N.
Thanks again!
  5 Comments
HpW
HpW on 25 Sep 2022
Hi
so lets say I put those variables in a single vector:
v = [10 15 1 20 25];
I still am not following how I can accomplish the task in this way either?
could u explain further?
thanks
Stephen23
Stephen23 on 25 Sep 2022
Edited: Stephen23 on 25 Sep 2022
"so lets say I put those variables in a single vector:"
As they should be.
"I still am not following how I can accomplish the task in this way either?"
ISMEMBER (hint: look at all of its outputs). You probably don't even need a loop.

Sign in to comment.

Accepted Answer

Image Analyst
Image Analyst on 25 Sep 2022
You forgot to attach your data. If it's secret, just mock up some dummy data.
Try strcmpi(), contains(), or ismember()
if strcmpi(var_names{i}, 'var1') && (var_values(i) > var_values(1))
% Do something
end
If you have any more questions, then attach your data and code to read it in with the paperclip icon after you read this:
  4 Comments
HpW
HpW on 28 Sep 2022
Thanks. This was very helpful. Is there a way to pull the values from the workspace into some structure automatically? If so I could deal with the fact that I only care about the variables listed in the csv file by doing something like this I think:
vars = whos
varNames = {vars.name}
S = struct;
for i = 1:length(var_names) % variables names from csv file
for j = 1:length(varNames) % variables names from workspace
if strcmp(varNames{j}, var_names{i})
S.varNames{j} = %value of variable varNames{j} - but dont know how to do this...
end
end
This would give me a structure S with only the variables/values from the csv file, but the transformation from a string variable name to the actual variable name seems to still be an issue, eg, I would need a way to get the values from the workspace automatically. If it helps, the values are all going to be doubles, nothing more complex than that.
Stephen23
Stephen23 on 1 Oct 2022
Edited: Stephen23 on 1 Oct 2022
"Is there a way to pull the values from the workspace into some structure automatically?"
Of course: by using EVAL (or equivalents).
But given that the title of your question is "Alternative to Eval for small number of variables", then you have not really gained anything at all, just performed the same operation in a more complex way.
"I would need a way to get the values from the workspace automatically."
The problem then is the data design.
How did you get all of those variables into the workspace in the first place?

Sign in to comment.

More Answers (2)

Jeff Miller
Jeff Miller on 25 Sep 2022
Put your workspace variables in a struct and then use var_names to access the fields of that struct, something like this:
wrkstruc.a = 5;
if wrkstruc.(var_names{1}) > var_values(1)
% do something
end
  1 Comment
HpW
HpW on 28 Sep 2022
Thanks. This does work assuming that I prepopulate the structure with the values from the workspace. Ideally I am looking for a way to do this without necessarily knowing the variables which will be listed in the csv file ahead of time. The workspace variables may change over time.

Sign in to comment.


Stephen23
Stephen23 on 26 Sep 2022
Edited: Stephen23 on 26 Sep 2022
Approaches like EVAL and structure fields for this task are far too complex.
You need to learn how to use arrays to write simple and efficient code, not fight MATLAB with complex data design.
Note that I changed the order of the rows in the CSV file, because providing that data in exactly the order a,b,c,d does not really make demonstrating or testing the soluton very... comprehensive. Non-trivial example data make the solution easier to illustrate.
T = readtable('filename.csv')
T = 4×2 table
Var1 Var2 _____ ____ {'a'} 5 {'c'} 15 {'b'} 10 {'d'} 20
V = [ 10; 15; 1; 20; 25];
C = ["a";"b";"c";"d";"e"];
[X,Y] = ismember(C,T.Var1); % MATLAB is so easy when you use arrays...
N = V(X) > T.Var2(Y(X)) % ... because then you can write simple and efficient code.
N = 4×1 logical array
1 1 0 0
Displaying the results (just for interest, not part of the solution):
compose("%s: %d",C(X),N)
ans = 4×1 string array
"a: 1" "b: 1" "c: 0" "d: 0"
Summary: use MATLAB arrays to write simple and efficient code. Your approach of forcing meta-data into variabe names (and using structure fields, etc) is far too complex for such a simple task. In case the message is not clear yet, you need to learn to use arrays to use MATLAB efficiently.
  2 Comments
HpW
HpW on 28 Sep 2022
Thanks. Your points are well taken. This does work assuming I have arrays V and C set ahead of time. The issue in my specific case is that the specific variable names in C may change over time and was looking for a way to future proof the code in case in the future someone wants to look at variable 'f'
Stephen23
Stephen23 on 1 Oct 2022
Edited: Stephen23 on 1 Oct 2022
"The issue in my specific case is that the specific variable names in C may change over time and was looking for a way to future proof the code in case in the future someone wants to look at variable 'f'"
That point does not make much sense to me: you will need to have the values defined before you can use them, so either they will need to be defined in some arrays (leading to simple and efficient MATLAB code) or they will need to be defined as lots of separate variables (your preferred approach, leading to slow, complex, inefficient, insecure, buggy code that is hard to debug).... but in either case, the values will need to be defined before you can use them.
"I have been reading about using (or not using) eval, but have a situation where I cannot figure out how to get around it."
The requirements you have given so far are contradictory: you want to access lots of variables by name without accessing variables by name (using EVAL et al). It should be clear that there is no solution to this.
The best approach by far would be to reconsider your data design.

Sign in to comment.

Products


Release

R2020b

Community Treasure Hunt

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

Start Hunting!