8
map1 = containers.Map({'212','2','12','44'},[4,5,6,7]);
keyset = str2double(keys(map1));

Now I do a set of operations on the keyset which will give back

Keyset= [203,2,12,39];

I tired the following:

num2cell(num2str(keyset));
num2cell(num2str(keyset,1));
num2cell(num2str(keyset,'%11.0g'));
num2cell(num2str(keyset,3));

all of the above gave weird results in the final cell array. I just need the integers to be used as keys for another container map.

1
  • 2
    So what is your desired result? Is it {'203', '2', '12', '39'}? Commented Dec 30, 2012 at 11:45

4 Answers 4

13

I propose 5 additional solutions, three of which are 4-5x faster by than the solutions proposed so far. The lessons learned from this are:

  • num2str is slow
  • cellfun and arrayfun can add significant overhead
  • There are many ways to convert a numeric array to a cell array of strings.

The three highest-performance solutions are very similar in terms of performance:

Looping to assign cell elements

n4 = length(Keyset);
tmp4 = cell(n4,1);
for i4 = 1:n4
    tmp4{i4} = sprintf('%i',Keyset(i4));
end

Converting all to string and calling textscan

tmp6 = textscan(sprintf('%i\n',Keyset'),'%s');
tmp6 = tmp6{1};

Converting all to string and calling regexp.

tmp3 = regexp(sprintf('%i ',Keyset),'(\d+)','match');

Here's the full test code with timings:

function t = speedTest

t=zeros(7,1);
for ii=1:100, 
    Keyset=randi(1,10,100); % random keys
    tic; 
    eval( [ 'tmp1 = { ', sprintf(' %d ', Keyset), ' }; '] );
    t(1)=t(1)+toc; 
    tic;
    tmp2=arrayfun(@num2str, Keyset, 'Uniform', false);
    t(2)=t(2)+toc;

    tic;
    tmp3 = regexp(sprintf('%i ',Keyset),'(\d+)','match');
    t(3) = t(3)+toc;

    tic;
    n4 = length(Keyset);
    tmp4 = cell(n4,1);
    for i4 = 1:n4
        tmp4{i4} = sprintf('%i',Keyset(i4));
    end
    t(4) = t(4)+toc;

    tic;
    n5 = length(Keyset);
    tmp5 = cell(n5,1);
    for i5 = 1:n5
        tmp4{i5} = num2str(Keyset(i5));
    end
    t(5) = t(5)+toc;

    tic;
    tmp6 = textscan(sprintf('%i\n',Keyset'),'%s');
    tmp6 = tmp6{1};
    t(6) = t(6)+toc;

    tic;
    tmp7 = num2cell(Keyset);
    tmp7 = cellfun(@(x)sprintf('%i',x),tmp7,'uni',false);
    t(7) = t(7)+toc;


end;
t

t =

    1.7820
   21.7201
    0.4068
    0.3188
    2.2695
    0.3488
    5.9186
Sign up to request clarification or add additional context in comments.

3 Comments

Yay, mine is the slowest! But how did we end up talking about performance here? :-)
@EitanT: It wasn't me! It was Shai who started it.
Just got the license server back. It works out great.. previously I also tried using sprintf('%11.0g',x). Thanks a lot..
7

How about:

arrayfun(@num2str, Keyset, 'Uniform', false)'

which should yield a 4-by-1 cell array for your example:

ans = 
    '203'
    '2'
    '12'
    '39'

4 Comments

@Shai not sure that the OP is looking for performance in this case.
this is why I added the "note" at the bottom - your solution is more "Matlab"ish than mine, but at a small cost of run-time...
@Shai I don't think it's more "Matlab"ish :) it's just shorter (and currently slower)
I am particularly font of all the *fun function: cellfun, arrayfun, strcutfun etc. I think they are more "Matlab"ish than evaluating an "on the fly" string... But maybe that's just me. Anyhow, +1 for nice solution.
3

How about:

eval( [ 'NewKeySetStr = { ', sprintf(' %d ', Keyset), ' }; '] );
NewKeySetStr

I'm not sure this is the most elegant way to achieve the desired results, but it seems to work...

Comparing runtime with Eitan's solution:

t=zeros(2,1);
for ii=1:100, 
    Keyset=randi(1,10,100); % random keys
    tic; 
    eval( [ 'NewKeySetStr = { ', sprintf(' %d ', Keyset), ' }; '] );
    t(1)=t(1)+toc; 
    tic;
    tmp=arrayfun(@num2str, Keyset, 'Uniform', false);
    t(2)=t(2)+toc;
end;
t

Yields:

t =
   0.3986
   2.2527

It seems like proposed solution is faster.

Note: it seems like current implementation of cellfun is not optimized for speed. It is rumored that in future versions Mathworks intends to introduce better implementation of cellfun. So, Eitan's solution might not be optimal in current version, but it seems to be a good practice of Matlab skills.

3 Comments

+1: Even though your solution employs eval, it's still fast. However, I wonder if it works for very large arrays. By the way, I believe that 0.3s differs from 2.2s by approx. one order or magnitude (not two).
It is very difficult not to give you a -1 for an evil solution. Fortunately, there are at least 3 solutions that are faster.
The slip of tongue was not by chance... :)
0

Figured out how to improve the regexp solution for large integers, using the split functionality. Also I was somewhat misled by one of Jonas's solutions, which didn't evaluate all sprintf calls in the for loop. Edit: also added the new 2016 string functionality suggested in the comments.

t = speedTest()

function t = speedTest

t=zeros(5,1);
for ii=1:100
    Keyset=randi(10000000,10,1000); % random keys

    tic;
    n4 = numel(Keyset); % changed to numel (length only gives number of columns)
    tmp1 = cell(n4,1);
    for i4 = 1:n4
        tmp1{i4} = sprintf('%i',Keyset(i4));
    end
    t(1) = t(1)+toc;

    tic;
    tmp2 = regexp(sprintf('%i ',Keyset),'(\d+)','match');
    t(2) = t(2)+toc;

    tic;
    tmp3 = regexp(sprintf('%i ',Keyset),' ','split');
    tmp3(end) = [];
    t(3) = t(3)+toc;

    tic;
    tmp4 = string(Keyset(:));
    t(4) = t(4)+toc;

    # test in case you want to go back to characters
    tic;
    tmp5 = char(string(Keyset(:)));
    t(5) = t(5)+toc;
end
end

The regexp solution with split yields slightly better performance, and the string method is even faster:

t =

    6.1916
    1.1292
    0.8962
    0.6671
    0.7523

2 Comments

Starting in 16b MATLAB has a string datatype. string(Keyset) is ~25% faster than your fastest case.
My initial experiment was using tmp4 = string(Keyset) which causes the destruction of the existing tmp4. When using a new variable, string(Keyset) is 40% faster than your fastest case.

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.