Matlab: Converting a double vector array to string cell array

18,750

Solution 1

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

Solution 2

How about:

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

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

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

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.

Share:
18,750
martin
Author by

martin

Updated on July 29, 2022

Comments

  • martin
    martin almost 2 years
    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.