2

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.

TNT
  • 2,431
  • 1
  • 19
  • 26
  • Do you always know before hand the indices of where the cells would be populated? For example, will you know that `results1` will populate cells 3 and 4 and will `results2` populate cell 1? Without this information, it's rather ambiguous on how you'd join the cells together if you used the contents of both fields for both structures. – rayryeng May 15 '15 at 06:10
  • Yes, as I mentioned the results are put into cells according to index, so a loop over 3:4 will populate cells 3 and 4 respectively. thats why `results1` has two empty leading cells. – TNT May 15 '15 at 10:22

3 Answers3

5

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
Mohsen Nosratinia
  • 9,844
  • 1
  • 27
  • 52
2

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.

Community
  • 1
  • 1
David
  • 8,449
  • 1
  • 22
  • 32
1

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
TNT
  • 2,431
  • 1
  • 19
  • 26