Найти значения в ячейке массива 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 2

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 полностью устарел; Пожалуйста, игнорируйте его :)