Merge structures with subfields

조회 수: 11 (최근 30일)
Jan
Jan 2015년 1월 10일
댓글: Jan 2015년 1월 13일
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
Jan
Jan 2015년 1월 12일
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?

댓글을 달려면 로그인하십시오.

채택된 답변

Guillaume
Guillaume 2015년 1월 12일
편집: Guillaume 2015년 1월 13일
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
Guillaume
Guillaume 2015년 1월 13일
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 2015년 1월 13일
Works like a charm! Thanks!

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Titus Edelhofer
Titus Edelhofer 2015년 1월 12일
편집: Titus Edelhofer 2015년 1월 12일
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

카테고리

Help CenterFile Exchange에서 Loops and Conditional Statements에 대해 자세히 알아보기

제품

Community Treasure Hunt

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

Start Hunting!

Translated by