如何将单元数组中所有的“string”类型替换为“char”类型?

24

上下文

在R2016b中,MATLAB引入了一种新的 字符串 数据类型,除了通常的字符数据类型。这样做很好,但现在它正在给我使用的JSONlab 工具箱带来很多问题。

例如,在R2015b中,loadjson 返回一个 1x3 的字符数组:

dd = loadjson('["Titi", "Toto", "Tata"]')

dd = 

    'Titi'    'Toto'    'Tata'

但是在 R2018a 中,loadjson 返回一个 1x3 的字符串数组:

dd = loadjson('["Titi", "Toto", "Tata"]')

dd =

  1×3 cell array

    {["Titi"]}    {["Toto"]}    {["Tata"]}

问题

为了不必在各处更改我的代码,我想修补loadjson例程,以将其返回的所有字符串类型替换为字符类型。例如,在以下单元数组中:

test = { 'hello', "world", 0.3; 'how', 'are', "you"}

test =

  2×3 cell array

    {'hello'}    {["world"]}    {[0.3000]}
    {'how'  }    {'are'    }    {["you" ]}

我想替换所有的字符串:

cellfun(@isstring, test)

ans =

  2×3 logical array

   0   1   0
   0   0   1

有没有一种方法可以快速完成它(即不需要循环所有元素)?

附注:我知道使用jsondecodejsonencode替换JSONLab是未来的方向,但到目前为止,我只想快速修复一些东西。


1
函数char将转换为字符数组。使用cellfun或类似方法将其应用于数组,然后使用您拥有的逻辑索引进行替换。 - Matt
2
Titi Toto 是新的 foo bar - Vanity Slug
4个回答

16

您可以使用cellstr(尽管 "str" 意味着字符串)将字符串转换为字符数组,而无需循环或cellfun...文档说明如下:

C = cellstr(A)A转换为字符向量的单元数组。输入数组A可以是字符数组、分类数组或从R2016b开始的字符串数组。

test = {'hello', "world", 0.3; 'how', 'are', "you"}; % multi-type test cell array
ind = cellfun(@isstring, test);                      % indexing for string type items
test(ind) = cellstr(test(ind))                       % char-ify the strings!

关于类检查的cellfun性能提示:

在我的答案和Luis的答案中,cellfun用于确定哪些元素是字符串。您可以提高cellfun在此任务中的性能...

根据cellfun文档,有一些字符数组选项比它们的函数句柄快得多。对于isstring索引,运行第一个选项可能会更快。

% rapid
ind = cellfun('isclass', test, 'string');
% akin to looping
ind = cellfun(@isstring, test);

它们有相同的输出,在一个简单的测试中,我看到了4倍的速度提升:

% Create large test array of random strings
c = cell(100,1000);
c = cellfun(@(x) string(char(randi([65,122],1,10))), c, 'uni', 0);

% Create functions for benchmarking 
f=@()cellfun('isclass', c, 'string');
g=@()cellfun(@isstring,c);

% Timing on MATLAB R2017b
timeit( f ) % >> 0.017sec
timeit( g ) % >> 0.066sec 

我已经为@LuisMendo验证过了,但那也是一个好的选择! :) - CitizenInsane
@CitizenInsane 接受标记从来没有被确定下来 ;) 公平地说,一些快速测试显示 cellfun 选项的速度与 cellstr 大致相同,因此唯一的优势是可读性。 - Wolfie
感谢您在速度优化方面进行额外的编辑和深入检查,以检查元素是否为“字符串”类型...您赢了 :) - CitizenInsane

11

您可以使用 cellfun,但它的性能与循环基本相同:

test = {'hello', "world", 0.3; 'how', 'are', "you"};
ind = cellfun(@isstring, test);
test(ind) = cellfun(@char, test(ind), 'UniformOutput', false)

真可惜,我已经接近了它,但是在 {}() 的语法中迷失了...谢谢 :) - CitizenInsane

11

从MATLAB R2017b开始,你可以使用convertstringstochars函数:

[test{:}] = convertStringsToChars(test{:});

1
我去掉了错别字和额外的空格,并在R2017b上进行了测试,它按预期工作(很好地将数字元素保留为数字,没有任何投诉)。 - Wolfie

8
另一种解决方案(在UndocumentedMATLAB博客中讨论),是使用controllib.internal.util.hString2Char的“半文档化”函数。以下是使用它的方法:
test = { 'hello', "world", 0.3; 'how', 'are', "you"};
fixed_test = controllib.internal.util.hString2Char(test);

fixed_test =

  2×3 cell array

    {'hello'}    {'world'}    {[0.3000]}
    {'how'  }    {'are'  }    {'you'   }

根据博客文章,此函数会递归地遍历输入内容,因此即使在以下情况下也可以正常工作:
test = {"target1", struct('field',{123,'456',"789"})};
ft = controllib.internal.util.hString2Char(test);
{ft{2}.field}

ans =

  1×3 cell array

    {[123]}    {'456'}    {'789'}

查看博客文章以了解一些注意事项。


1
我从未想过在将字符串转换为字符时会有这么多好的不同答案! :) - CitizenInsane
1
@CitizenInsane 因引入新的数据类到几十年历史的编程语言中而带来的成长烦恼 :) - sco1

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