Merge structures with subfields

11 vues (au cours des 30 derniers jours)
Jan
Jan le 10 Jan 2015
Commenté : Jan le 13 Jan 2015
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
  1 commentaire
Jan
Jan le 12 Jan 2015
Ok maybe I should rephrase my problem a bit, I'm looking for a way to index nested fields in a structure. Suppose I have s.a.b.c
Is there a smart way without for-loopt to index these structures?

Connectez-vous pour commenter.

Réponse acceptée

Guillaume
Guillaume le 12 Jan 2015
Modifié(e) : Guillaume le 13 Jan 2015
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
  3 commentaires
Guillaume
Guillaume le 13 Jan 2015
Hum, the code I've attached works with any number of levels of nested structure. Have you tried it?
%generate demo data:
s(1) = struct('time', [0:239]', 'a', struct('b', struct('c', reshape(1:240*3, 240, 3), 'd', -reshape(1:240*3, 240, 3))));
s(2) = struct('time', [0:119]', 'a', struct('b', struct('c', 1000+reshape(1:119*3, 119, 3), 'd', -1000-reshape(1:119*3, 119, 3))));
s(3) = struct('time', [0:59]', 'a', struct('b', struct('c', 2000+reshape(1:59*3, 59, 3), 'd', -2000-reshape(1:59*3, 59, 3))));
s(1).a.very.deeply.nested.field.in.the.structure = [1 2 3];
s(2).a.very.deeply.nested.field.in.the.structure = [4 5 6];
s(3).a.very.deeply.nested.field.in.the.structure = [7 8 9];
news = CatStructByTime(s, 'time');
news =
time: [420x1 double]
a: [1x1 struct]
news.a.very.deeply.nested.field.in.the.structure
ans =
1 2 3
4 5 6
7 8 9
Note, there was a small bug in the code which I've fixed.
Jan
Jan le 13 Jan 2015
Works like a charm! Thanks!

Connectez-vous pour commenter.

Plus de réponses (1)

Titus Edelhofer
Titus Edelhofer le 12 Jan 2015
Modifié(e) : Titus Edelhofer le 12 Jan 2015
Hi Jan,
it probably might be too easy (that's why I don't try here ;-)), but my guess is, that with a recursive call you might be better off.
It could be though that you have to carry the time vector down the levels with you, i.e., instead of recursively calling your function with in.(fieldnames{1}), you will create an intermediate structure
inIntermediate = struct(timename, in.(timename), fieldnames{1}, in.(fieldnames{1}));
which then is used to call the function recursively.
Maybe this helps...
Titus

Catégories

En savoir plus sur Loops and Conditional Statements dans Help Center et File Exchange

Produits

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by