Matlab: преобразование двойного векторного массива в массив строковых ячеек

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

Теперь я делаю набор операций над набором ключей, который вернет

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

Я устал от следующего:

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

все вышеперечисленное дало странные результаты в конечном массиве ячеек. Мне просто нужно, чтобы целые числа использовались в качестве ключей для другой карты контейнера.

4 ответов


Я предлагаю 5 дополнительных решений, три из которых 4-5x быстрее, чем решения, предложенные до сих пор. Из этого можно извлечь следующие уроки:--10-->

  • num2str медленно
  • cellfun и arrayfun может добавить значительные накладные расходы
  • существует много способов преобразования числового массива в массив ячеек строк.

три высокопроизводительных решения очень похожи с точки зрения производительности:

зацикливание на назначить элементы ячейки

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

преобразование всех в строку и вызов textscan

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

преобразование всех в строку и вызов regexp.

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

вот полный тестовый код с таймингами:

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

Как насчет:

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

который должен дать массив ячеек 4 на 1 для вашего примера:

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

как насчет:

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

Я не уверен, что это самый элегантный способ достижения желаемых результатов, но, похоже, это работает...

сравнение времени выполнения с решением Eitan:

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

выходы:

t =
   0.3986
   2.2527

кажется, что предлагаемое решение быстрее.

Примечание: похоже, что текущая реализация cellfun не оптимизирован по скорости. Ходят слухи, что в будущих версиях Mathworks намерена представить лучше реализация cellfun. Таким образом, решение Eitan может быть не оптимальным в текущей версии, но, похоже, это хорошая практика навыков Matlab.


выяснил, как улучшить решение regexp для больших целых чисел, используя функцию разделения. Кроме того, меня несколько ввело в заблуждение одно из решений Джонаса, которое не оценивало все вызовы sprintf в цикле for. Edit: также добавлена новая функциональность строки 2016, предложенная в комментариях.

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

решение regexp с разделением дает немного лучшую производительность, а строковый метод еще быстрее:

t =

    6.1916
    1.1292
    0.8962
    0.6671
    0.7523