Matlab:将双精度向量数组转换为字符串单元格数组

8
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));

以上所有内容在最终的单元数组中都给出了奇怪的结果。我只需要将整数用作另一个容器映射的键。


2
那么你想要的结果是什么?是 {'203','2','12','39'} 吗? - Eitan T
4个回答

13

我提出了5个额外的解决方案,其中三个比目前提出的解决方案快4-5倍。从中学到的教训是:

  • num2str 很慢
  • cellfunarrayfun 可能会增加很大开销
  • 有很多方法可以将数字数组转换为字符串单元格数组。

在性能方面表现最好的三个解决方案非常相似:

循环分配单元格元素

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

耶,我的最慢!但我们怎么会在这里谈论性能呢? :-) - Eitan T
@EitanT:不是我!是Shai开始的。 - Jonas
刚刚恢复了许可证服务器。它运行得非常好。之前我也尝试过使用sprintf('%11.0g',x)。非常感谢。 - martin

7
怎么样:
arrayfun(@num2str, Keyset, 'Uniform', false)'

您的示例应该能够产生一个 4x1 的单元数组:
ans = 
    '203'
    '2'
    '12'
    '39'

@Shai 不确定原帖作者在这种情况下是否正在寻求性能。 - Eitan T
这就是为什么我在底部添加了“注释”的原因 - 你的解决方案更加“Matlab”,但运行时间略有增加... - Shai
@Shai 我不认为它更像“Matlab” :) 它只是更短(而且目前更慢) - Eitan T
1
我特别喜欢所有的 *fun 函数:cellfunarrayfunstrcutfun 等等。我认为它们比动态字符串求值更符合 "Matlab" 风格... 但也许这只是我的想法。无论如何,对于这个好的解决方案,我给一个加一。 - Shai

3
如何考虑:
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技能的良好实践。


+1:尽管您的解决方案使用了“eval”,但仍然很快。不过,我想知道它是否适用于非常大的数组。顺便说一句,我相信“0.3秒”与“2.2秒”相差约一个数量级(而不是两个)。 - Eitan T
很难不给你一个-1的“邪恶”解决方案。幸运的是,至少有3个更快的解决方案。 - Jonas
1
口误不是偶然的... :) - Eitan T

0
找到了如何使用分割功能来改进大整数的正则表达式解决方案。 同时,我被 Jonas 的一个解决方案误导了,它没有在 for 循环中评估所有 sprintf 调用。 编辑:还添加了评论中建议的新的 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

使用split的正则表达式解决方案性能略好,而字符串方法甚至更快:

t =

    6.1916
    1.1292
    0.8962
    0.6671
    0.7523

从16b MATLAB开始,它有了字符串数据类型。string(Keyset) 比您最快的情况快约25%。 - matlabbit
1
我的初始实验是使用tmp4 = string(Keyset),这将导致现有的tmp4被破坏。当使用一个新变量时,string(Keyset)比您最快的情况快40%。 - matlabbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接