Alternative to Eval for small number of variables

6 visualizzazioni (ultimi 30 giorni)
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 Commenti
HpW
HpW il 25 Set 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 il 25 Set 2022
Modificato: Stephen23 il 25 Set 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.

Accedi per commentare.

Risposta accettata

Image Analyst
Image Analyst il 25 Set 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 Commenti
HpW
HpW il 28 Set 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 il 1 Ott 2022
Modificato: Stephen23 il 1 Ott 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?

Accedi per commentare.

Più risposte (2)

Jeff Miller
Jeff Miller il 25 Set 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 Commento
HpW
HpW il 28 Set 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.

Accedi per commentare.


Stephen23
Stephen23 il 26 Set 2022
Modificato: Stephen23 il 26 Set 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 Commenti
HpW
HpW il 28 Set 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 il 1 Ott 2022
Modificato: Stephen23 il 1 Ott 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.

Accedi per commentare.

Prodotti


Release

R2020b

Community Treasure Hunt

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

Start Hunting!

Translated by