1

I have a cell with mathematical expressions that I would like to convert to a numeric array. It look as follows:

a = {};
a{1,1} = '0.55';
a{2,1} = '0.25 + 0.50';

Now I would like to receive the result (but preferably without a for loop):

b(1) = 0.55;
b(2) = 0.75;

How can I achieve this efficiently?

3
  • 4
    "efficient" would be to restructure your code to not rely on string-evaluation at all, because that involves eval. On why eval is almost a bad idea, see this answer of mine. This is very reminiscent of an XY problem, so please, ask about the problem, not your proposed solution if you want a meaningful answer on efficiency, as opposed to a very slow and crude stitch. Commented Nov 21, 2018 at 9:24
  • 1
    As a simple way to notice why eval can be bad, assume a{1,1}='exit'. For a less damaging example, assume it has a mathematical expression that results in an infinite loop,or something of the likes. Commented Nov 21, 2018 at 9:43
  • What about str = [ '[' , sprintf('%s ',a{:}) '];'];b = eval(str); ? Commented Nov 21, 2018 at 10:37

1 Answer 1

2

b = cellfun(@eval,a); will create an array b of the same size as cell array a, with each value the evaluation of the corresponding string in the cell array.

a = {};
a{1,1} = '0.55';
a{2,1} = '0.25 + 0.50';

a=repmat(a,1000,20); %Make it big for performance evaluation

tic
b1 = cellfun(@eval,a);
toc %0.662187 seconds

Another option is to make a big string expression so that eval is called only once rather than several times due to cellfun internal loop. This is less safe as abnormal values in the cell array a will likely cause the code to crash, while it may simply produce NaN in the code above.

tic
% add a comma separator after each value
strCell = cellfun(@(x) [x ','],transpose(a),'uniformoutput',false);
% add a semicolon separator at the end of each row
strCell(end,:) = cellfun(@(x) [x(1:end-1) ';'], strCell(end,:), 'uniformoutput',false);
% remove the last separator
strCell{end}=strCell{end}(1,end-1);
% evaluate the line
b2=eval(['[' strCell{:} ']']);
toc %0.313738 seconds but sometimes more than 1 seconds
Sign up to request clarification or add additional context in comments.

6 Comments

Using eval is not so efficient. See nl.mathworks.com/help/matlab/matlab_prog/string-evaluation.html. Are there better ways/quicker?
There are not that many string evaluation functions. str2num internally relies on eval and will not be more efficient (edit str2num to see the actual code). str2double does not work on expressions
You'll want to put a large warning here that eval is nearly always harmful for speed in your code. I agree that it's the sole option here, but one cannot warn people enough to try and avoid having to use eval whenever possible, see e.g. this answer of mine and links therein on why this is the case.
At least I learned something new here; cellfun does support eval. Not that that makes it any better for use of course. Also note that cellfun is just a MATLAB wrapper around a loop, not even a FORTRAN loop. So whilst technically you're not writing the loop yourself, MATLAB still uses a slow, high-level loop (as opposed to vectorisation, which employs low-level FORTRAN loops).
@Adriaan cellfun is nothing more than a high level loop, except for those functions listed in the 'Backward compatibility' paragraph of the documentation: isempty, islogical, isreal, length, ndims, prodofsize, size, isclass. If these are passed as a string rather than a function handle, the performance of the function is greatly enhanced (which indicates some low-level loop is being used). Like, cellfun('isempty',C) is way faster than cellfun(@isempty,C)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.