Найти значения в ячейке массива struct
У меня есть два массива ячеек со структурой в нем.
Пример:
xmlFB = Columns 1 through 5 [1x1 struct] [1x1 struct] [1x1 struct] [1x1 struct] [1x1 struct]Xmllink = Columns 1 through 3 [1x1 struct] [1x1 struct] [1x1 struct]
XmlFB{1} ans =
Param: {[1x1 struct] [1x1 struct]} InterChartConnection: [1x1 struct] Tasks: [1x1 struct] Attributes: [1x1 struct] xmllink{1} ans = Attributes: [1x1 struct]
В "xmllink "есть структура" атрибуты "и в поле" имя "со значением" EN1 "
И в xmlFB в структуре "атрибуты "есть два поля" имя " и " Тип "
Имена уникальны.
Что я хочу сделать, так это найти "Тип " в "xmlFB " из имен в " xmllink".
Сначала я хотел сделать с циклом, но я прочитал об этих функциях arrayfun / structfun/cellfun из Matlab.
Есть ли способ сделать это с этими? Или петля лучше?2 ответа:
Предположим, что все переменные в именах и типах являются строками. (Должно работать и для скаляров.)
Вот как получить значения в массивы ячеек и связать их.
Поскольку порядок значений в первых клеточных массивах будет таким же, как и в исходных клеточных массивах структур, вы можете использовать эти индексы% create cell arrays xmllinkname = cellfun(@(x) x.Attributes.Name, xmllink, 'UniformOutput',0); xmlFBname = cellfun(@(x) x.Attributes.Name, xmlFB, 'UniformOutput',0); xmlFBtyp = cellfun(@(x) x.Attributes.Typ, xmlFB, 'UniformOutput',0); % match names [idx1, idx2] = ismember(xmllinkname,xmlFBname); idx2(idx2==0)=[]; % in case some names in xmllink absent in xmlFB % get matched names and typ xmllinknamematched = xmllinkname(idx1); xmllinktyp = xmlFBtyp(idx2);
idx1
иidx2
для сопоставления структур.xmllinkmatched = xmllink(idx1); xmlFBmatched = xmlFB(idx2);
Конечно, можно избежать создания временных массивов и поставить первые два оператора
cellfun
в утверждениеismember
.
Используйте цикл.
Прежде всего: начинайте беспокоиться о производительности только тогда, когда это действительно проблема, и только после того, как ты все правильно понял.
Теперь, если я правильно вас понял, вот, как правило, два способа выполнить то, что вы хотите:% create some bogus data with the same structure % --------------------------- f_xmllink = @(N) struct(... 'Attributes', struct(... 'Name', num2str(N))... ); f_xmlFB = @(N) struct(... 'Attributes', struct(... 'Name', num2str(N),... 'Typ' , num2str(N))... ); % using numbers as names xmllink = { f_xmllink(190) f_xmllink(331) % 2 f_xmllink(321) % 3 f_xmllink(239) }; xmlFB = { f_xmlFB(331) % 1 f_xmlFB(200) f_xmlFB(108) f_xmlFB(321) % 4 f_xmlFB(035) }; % Example of a no-loop approach % --------------------------- tic s_exp = @(s, field) [s.(field)]; s_exp_C = @(s, field) {s.(field)}; one = s_exp_C(s_exp( [xmllink{:}], 'Attributes'), 'Name'); two = s_exp_C(s_exp( [xmlFB{:}], 'Attributes'), 'Name'); [i,j] = find(strcmp(repmat(one,numel(two),1), repmat(two,numel(one),1).')); s_exp_C(s_exp([xmlFB{i}], 'Attributes'), 'Typ') toc % Example of a loop approach % --------------------------- tic for ii = 1:numel(xmllink) S = [xmlFB{:}]; S = [S.Attributes]; S = {S.Name}; ind = strmatch(xmllink{ii}.Attributes.Name, S); if ~isempty(ind) xmlFB{ind}.Attributes.Typ end end toc
Вывод:
Конечно, это нечестный тест для сравнения производительности, но я думаю, что все согласятся, что зацикленная версия по крайней мере не будет медленнее , чем версия без цикла.% no-loop ans = '331' '321' % correct findings Elapsed time is 0.001103 seconds. % loop ans = 331 % correct findings ans = 321 Elapsed time is 0.000666 seconds. % FASTER!
Что еще более важно, скорость-это еще не все - сколько времени вам потребовалось, чтобы понять решение без цикла? Скорее всего, вы поняли решение цикла в одном чтении, тогда как решение без цикла намного сложнее и должно быть тщательно документировано и протестировано и т. д. Кроме того, изменения в решении без цикла будет сложнее реализовать, чем изменения в решении цикла.
Этот совет не использовать циклы в Matlab полностью устарел; Пожалуйста, игнорируйте его :)