【问题标题】:Matlab: Converting a double vector array to string cell arrayMatlab:将双向量数组转换为字符串单元格数组
【发布时间】:2012-12-30 11:38:45
【问题描述】:
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));

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

【问题讨论】:

  • 那么你想要的结果是什么?是{'203', '2', '12', '39'}吗?

标签: arrays string matlab double cell


【解决方案1】:

我提出了 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

【讨论】:

  • 是的,我的是最慢的!但是我们最终是如何在这里谈论性能的呢? :-)
  • @EitanT:不是我!是 Shai 发起的。
  • 刚刚取回了许可证服务器。效果很好.. 以前我也尝试过使用 sprintf('%11.0g',x)。非常感谢..
【解决方案2】:

怎么样:

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

应该为您的示例生成一个 4×1 元胞数组:

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

【讨论】:

  • @Shai 不确定 OP 在这种情况下是否正在寻找性能。
  • 这就是我在底部添加“注释”的原因 - 你的解决方案比我的更“Matlab”,但运行时间成本很小......
  • @Shai 我不认为它更像“Matlab”ish :) 它只是更短(并且目前更慢)
  • 我特别喜欢所有*fun 函数:cellfunarrayfunstrcutfun 等。我认为它们比评估“动态”更“Matlab”字符串...但也许这只是我。无论如何,+1 是很好的解决方案。
【解决方案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.3s2.2s 相差大约。一个数量级(不是两个)。
  • 对于evil 解决方案,很难不给你一个-1。幸运的是,至少有 3 个更快的解决方案。
  • 口误不是偶然... :)
【解决方案4】:

想出了如何使用拆分功能改进大整数的正则表达式解决方案。 此外,我被 Jonas 的一个解决方案误导了,该解决方案没有评估 for 循环中的所有 sprintf 调用。 编辑:还添加了 cmets 中建议的新 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

带有拆分的正则表达式解决方案的性能稍好,字符串方法更快:

t =

    6.1916
    1.1292
    0.8962
    0.6671
    0.7523

【讨论】:

  • 从 16b 开始,MATLAB 具有字符串数据类型。 string(Keyset) 比最快的情况快约 25%。
  • 我最初的实验是使用 tmp4 = string(Keyset) 导致现有 tmp4 的破坏。使用新变量时,string(Keyset) 比最快的情况快 40%。
猜你喜欢
  • 1970-01-01
  • 2014-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多