TNT
TNT

Reputation: 2511

merge structure field cells in matlab

I want to merge structure fields in case I do partial computations, to later fill up the whole structure field cells.

The results are put into cells according to index into the cell, like this:

for i=3:4;
results1.index{i}=i;
results1.sqr{i}=i*i;
end
for i=1;
results2.index{i}=i;
results2.sqr{i}=i*i;
end

giving, respectively:

results1 = 

    index: {[]  []  [3]  [4]}
      sqr: {[]  []  [9]  [16]}

results2 = 

    index: {[1]}
      sqr: {[1]}

is there a way to merge the resulting structures to obtain

allresults.index={[1] [] [3] [4]}
allresults.sqr={[1] [] [9] [16]}

I can avoid overlapping results, so no conflict resolution or overwriting in case of conflicting values (e.g. none of the cells are empty) would be ok. Please note that in the larger dataset, cells are not limited to scalars but may contain cells or other types.

Upvotes: 2

Views: 192

Answers (3)

TNT
TNT

Reputation: 2511

Both answers work. So I took the simplicity of Mohsen with the one-step approach of David and combined:

function C = structCat2(A,B)

F=fieldnames(A);
for k = 1:numel(F), 
    f = F{k}; 
    IA = ~cellfun('isempty',A.(f));
    IB = ~cellfun('isempty',B.(f));
    C.(f)(IA) = A.(f)(IA);
    C.(f)(IB) = B.(f)(IB);
end

Upvotes: 1

Mohsen Nosratinia
Mohsen Nosratinia

Reputation: 9864

You can first write a small helper function to merge the cells:

function R = mergeCells(A,B)
R = {};
IA = ~cellfun('isempty',A);
IB = ~cellfun('isempty',B);
R(IA) = A(IA);
R(IB) = B(IB);
end

and then call it in a loop to merge the fields

for k = 1:numel(F), 
    f = F{k}; 
    allresults.(f) = mergeCells(results1.(f), results2.(f)); 
end

Upvotes: 5

David
David

Reputation: 8459

Here's a function to accomplish this. I think it is fairly general, and it does deal with strings but does assume no conflicts. It will fail if the struct's have different field names or a different number of fields. I can't tell you anything about performance or whether there are better ways to do this.

function T = structCat(re1,re2)
F=fieldnames(re1);
for i=1:length(F) %// Do one field name at a time
    t1=re1.(F{i}); %// These are the individual cell arrays we are combining
    t2=re2.(F{i});
    if length(t2)>length(t1)
        %// This loop just makes t1 be the longest cell array, it's a bit messy though
        t1a=t1;
        t1=t2;
        t2=t1a;
    end
    T.(F{i})=t1; %// Now we know t1 is longer, set the new array to t1 initially
    for j=1:length(t2) %// Do each element of t2 individually
        if ~exist(T.(F{i}){j},'var') %// see if there is an element of t2 to insert into T
            T.(F{i}){j}=t2{j}; %// if there is, insert it!
        end
    end 
end
end

Usage is, for example,

for i=3:4;
    re1.index{i}=i;
    re1.index2{i}=i^2;
    re1.strings{i}='dafsd';
    re1.mat{i}=[i;2*i;3*i];
end
for i=1;
    re2.index{i}=i;
    re2.index2{i}=i^2;
    re2.strings{i}='hmmm';
    re2.mat{i}=[i;2*i;3*i].^2;
end

T=structCat(re1,re2)

which results in

T = 
      index: {[1]  []  [3]  [4]}
     index2: {[1]  []  [9]  [16]}
    strings: {'hmmm'  []  'dafsd'  'dafsd'}
        mat: {[3x1 double]  []  [3x1 double]  [3x1 double]}

You should also check out this question and this entry in the Matlab File Exchange, although I think they do slightly different things.

Upvotes: 2

Related Questions