Moosli
Moosli

Reputation: 3275

Find Values in cell array of struct

I have two cell array's with structure in it.

example:

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]

In "xmllink" there is the struct "Attributes" and in there is the Field "Name" with the Value "EN1"

And in xmlFB in the struct "Attributes" there are two Fields "Name" and "Typ"

The Names are unique.

What i want to do is to find the "Typ" in "xmlFB" from the names in the "xmllink".

First i wanted to do with a Loop, but the i read about these arrayfun/structfun/cellfun functions from Matlab.

Is there a way to do this with these? Or is a Loop better?

Upvotes: 2

Views: 2057

Answers (2)

yuk
yuk

Reputation: 19870

Let's assume that all variables in Names and Typ are strings. (Should work for scalars as well.)

Here is how to get the values into cell arrays and link them.

% 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);

Since the order of values in the first cell arrays will be the same as in your original cell arrays of structures, you can use those indices idx1 and idx2 to match the structures as well.

xmllinkmatched = xmllink(idx1);
xmlFBmatched = xmlFB(idx2);

Of course, you can avoid creating the temporary arrays and put the first two cellfun statement into ismember statement.

Upvotes: 3

Rody Oldenhuis
Rody Oldenhuis

Reputation: 38032

Use the loop.

First things first: only start worrying about performance when it is actually a problem, and only after you get it right.

Now, if I understood you correctly, here are generally two ways to accomplish what you want:

% 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

Output:

% 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!

Granted, it's not a fair test to compare the performance, but I think everyone will agree that the looped version will at the very least not be slower than the non-loop version.

More importantly, speed isn't everything -- how long did it take you to understand the no-loop solution? Chances are you understood the loop solution in one read, whereas the no-loop solution is a lot more complicated and will have to be thoroughly documented and tested etc. Also, changes to the no-loop solution will be harder to implement than changes in the loop solution.

That advice to not use loops in Matlab is completely outdated; please ignore it :)

Upvotes: 1

Related Questions