MATLAB: Alternative to using 'eval' in ord

2019-07-20 20:26发布

问题:

I have a bunch of char arrays within a cell array that actually represents the declaration of MATLAB structs. Something like this:

tmp{1} = 'testData.input = [1;2;3;4;5]'
tmp{2} = 'testData.output = [2;4;6;8;10]'

I need to execute these "commands" and eventually create the respective struct. I am using the eval function within a for-loop and it works.

numEntries = numel(tmp);
for i = 1 : numEntries
    eval(tmp{i});
end

However, this is painfully slow. I should mention that the real char arrays are very large, effectively containing more than 3,000 numbers. Also, the tmp cell array itself contains some 25,000 cells. Is there a way to improve performance given that I can't change the input data, i.e. tmp is simply given from an external source?

回答1:

I cannot test if it is significantly faster with only the 2 lines you gave as an example but I would expect this method to be faster when the number of elements of tmp grows.

The idea is to write all the assignment instructions contained into tmp into a text file (an .m file actually), then simply execute the .m file. For large number of lines I would expect that to be way faster than having to invoque eval repeatedly in a loop.

So here goes, this works fine with your example tmp, you end up with the structure testData in your workspace.

%% Create an '.m' file containing all the assignment instructions from the cell array
tmpFile  = 'tmpFile2execute.m' ;
fidw = fopen( tmpFile , 'w' ) ;
fprintf(fidw,'%% Auto generated file\n'); % or any other header line you want, or none...
for i = 1 : numel(tmp) ;
    fprintf(fidw,'%s ;\n',tmp{i});
end
fclose(fidw) ;
% (optional) only to keep workspace tidy
clear i fidw tmpFile tmp 

%% Execute the file
tmpFile2execute ;

Expanding on the idea you could make it a function instead of a script, where you could add some post processing and return the result in a variable instead of directly in the workspace but you have to see if the base idea brings any speed improvment first.



回答2:

cellfun(@eval,tmp); will somewhat improve the performance over a loop. Otherwise, you may have to write your own parser (which may be faster if a limited type of input is expected, e.g. only assignment like structure.some_field.some_other_subfield = [some_array]; ).

Please note that eval is a risky function to use (if Mr. Mischief writes in the input data something like !rm -Rf / , !del *.* or rmdir(matlabroot,'s') you may end-up with a big mess evaluating those strings)