MATLAB: Merge structures with subfields

concatenatefieldsMATLABstructures

Hi guys,
I have multiple structures (around 50, with equal fieldnames). Some fields go up to three levels deep (s.a.b.c). I want to concatenate all the fields. So suppose I have:
s1.time = [240x1 double]
s1.a.b.c = [240x3 double]
s1.a.b.d = [240x3 double]
s2.time = [120x1 double]
s2.a.b.c = [120x3 double]
s2.a.b.d = [120x3 double]
I want to achieve:
s3.time = [360x1double]
s3.a.b.c = [360x3 double]
s3.a.b.d = [360x3 double]
In s3 the time should be increasing while in s1 and s2 the time starts at 0 everytime. I wrote the following which works up till 3 levels but I have the idea this could be done much simpler..
function [ out ] = Concatenate_3rd_level_structs( in , timename)
%UNTITLED Summary of this function goes here
% Detailed explanation goes here
fieldsL1 = fieldnames(in); % Level 1 fields
out = in(1);
for i = 2:length(in)
for j = 1:length(fieldsL1)
if strcmp(fieldsL1{j},timename)
out.(timename) = [out.(timename); in(i).(timename)+out.(timename)(end)+out.(timename)(2)]; % For the time vector create an increasing signal
else
if isstruct(in(i).(fieldsL1{j}))
fieldsL2 = fieldnames(in(i).(fieldsL1{j}));
else
fieldsL2 = [];
end
if ~isempty(fieldsL2) % In case of a level 2 nested structure
for jj = 1:length(fieldsL2)
if isstruct(in(i).(fieldsL1{j}).(fieldsL2{jj}))
fieldsL3 = fieldnames(in(i).(fieldsL1{j}).(fieldsL2{jj}));
else
fieldsL3 = [];
end
if ~isempty(fieldsL3)% In case of a level 3 nested structure
for jjj = 1:length(fieldsL3)
out.(fieldsL1{j}).(fieldsL2{jj}).(fieldsL3{jjj}) = ...
[ out.(fieldsL1{j}).(fieldsL2{jj}).(fieldsL3{jjj}); in(i).(fieldsL1{j}).(fieldsL2{jj}).(fieldsL3{jjj})];
end
else
out.(fieldsL1{j}).(fieldsL2{jj}) = [out.(fieldsL1{j}).(fieldsL2{jj}); in(i).(fieldsL1{j}).(fieldsL2{jj})] ;
end
end
else
out.(fieldsL1{j}) = [out.(fieldsL1{j}); in(i).(fieldsL1{j})] ;
end
end
end
end
end

Best Answer

You'd have to use a loop for sure. As Titus say, I'd also use recursivity. What I would also do inside the recursive bit is operate on cell arrays of scalar structures instead of a structure array
function out = CatStructByTime(in ,timename)
%in: a structure array with at least one field called 'timename'
for field = fieldnames(in)'
field = field{1};
if strcmp(field, timename)
reftime = {in(:).(timename)}';
offsets = num2cell(cumsum([0; cellfun(@(tv) sum(tv([2 end])), reftime(1:end-1))]));
out.(field) = cell2mat(cellfun(@(tv, o) tv+o, reftime, offsets, 'UniformOutput', false));
else
out.(field) = CatStructRecurse(arrayfun(@(s) s.(field), in, 'UniformOutput', false));
end
end
end
function out = CatStructRecurse(sc)
%sc: a cell array of scalar structures
if isstruct(sc{1})
for field = fieldnames(sc{1})'
field = field{1};
out.(field) = CatStructRecurse(cellfun(@(s) s.(field), sc, 'UniformOutput', false));
end
else
out = vertcat(sc{:});
end
end