Как заменить весь тип "string" на "char" в массиве ячеек?

контекст

В R2016b MATLAB ввел новый тип данных строки в дополнение к обычному типу данных char. Пока что так хорошо, но теперь у меня много проблем с используемым ящиком 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 чтобы заменить все типы string которые он может вернуть с помощью типов char. Например, в следующем массиве ячеек:

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

Есть ли способ, которым я могу сделать это быстро (т.е. Без перебора всех элементов)?

PS: Я знаю jsondecode и jsonencode для замены JSONLab в будущем, но пока я просто хочу быстро исправить ситуацию.

Ответ 1

Вы можете использовать cellstr (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 эффективности cellfun для проверки класса:

Как в моих, так и в ответах Луиса, cellfun используется для определения того, какие элементы являются строками. Вы можете улучшить производительность 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 
[email protected]()cellfun('isclass', c, 'string');
[email protected]()cellfun(@isstring,c);

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

Ответ 2

Вы можете использовать cellfun, но он имеет более или менее ту же производительность, что и цикл:

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

Ответ 3

На MATLAB R2017b вы можете использовать convertstringstochars:

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

Ответ 4

Другое решение, обсуждаемое в блоге 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'}

Взгляните на сообщение в блоге для некоторых оговорок.