Any simple way to change a struct with fields of length "n" to a struct of length"n"?
8 ビュー (過去 30 日間)
古いコメントを表示
I have 2 structs each containing a field called 'time', along with other differently named fields of length "n"
i.e.
Mystruct.time = [1 4 6 8 9]
Mystruct.field2 = [5 6 7 8 9]
Mystruct.field3 = [23 423 2 4 7]
Yourstruct.time = [3 7]
Yourstruct.fieldX = [5 6]
What I need to do is create a time ordered "orderedStruct" that contains each index of these two structs, ordered by their time fields.
e.g. in this example I could type in "orderedStruct(num)" and could get the result:
orderedStruct(1) = struct with fields 'time' = 1, 'field2' = 5; 'field3' = 23;
orderedStruct(2) = struct with fields 'time' = 3, 'fieldX' = 5
orderedStruct(7) = struct with fields 'time' = 9, 'field2' = 9; 'field3' = 7;
Is there an efficient way to do this? I can imagine putting everything in a nested loop, from 1:number of structs and within that loop another going from 1:number of fields, but my structs could have 300 fields, with length of 50,000 or more. This would be a huge time hog.
Any ideas?
Thanks in advance
5 件のコメント
Guillaume
2016 年 3 月 11 日
Note that in an array of structure, all structures must have the same fields, so in your example orderedStruct must also have field2 and field3. What value should these be?
回答 (3 件)
Jos (10584)
2016 年 3 月 11 日
This question clearly shows how not thinking about your data management in the beginning will get you into trouble later on.
What do you want to have as the value of a field for which there is no time point ...?
3 件のコメント
Guillaume
2016 年 3 月 11 日
Regarding your latest comment, there is of course a simpler way to achieve the same thing, without eval and only looping once over the structures:
MyStruct = struct('Time', [1 4 6 8 9], 'field2', [5 6 7 8 9], 'field3', [23 423 2 4 7]);
YourStruct = struct('Time', [3 7], 'fieldX', [5 6]);
allstructs = {MyStruct, YourStruct}; %store structures in a cell array so we can iterate over them.
reshapedstructs = cell(size(allstructs));
timings = cell(size(allstructs));
%transform each struct from a struct of arrays into an array of structs of scalars
for sidx = 1:numel(allstructs)
fn = fieldnames(allstructs{sidx});
svalues = cell2mat(struct2cell(allstructs{sidx}));
reshapedstruct = cell2struct(num2cell(svalues), fn, 1); %the vertcat will fail if fields of the struct have different size
reshapedstructs{sidx} = num2cell(reshapedstruct'); %split the array of structs into a row cell array of scalar struct
timings{sidx} = allstructs{sidx}.Time;
end
%flatten the cell arrays and reorder by timing
reshapedstructs = [reshapedstructs{:}];
timings = [timings{:}];
[~, order] = sort(timings);
reshapedstructs = reshapedstructs(order);
celldisp(reshapedstructs)
A similar way to achieve the same in even less lines of code, but probably slower:
allstructs = {MyStruct, YourStruct};
reshapedstructs = cellfun(@(s) num2cell(cell2struct(num2cell(cell2mat(struct2cell(s))), ...
fieldnames(s), 1)'), allstructs, ...
'UniformOutput', false);
timings = cellfun(@(s) s.Time, allstructs, 'UniformOutput', false);
reshapedstructs = [reshapedstructs{:}];
timings = [timings{:}];
[~, order] = sort(timings);
reshapedstructs = reshapedstructs(order);
celldisp(reshapedstructs)
0 件のコメント
Kelly Kearney
2016 年 3 月 11 日
How about this?
A.time = [1 4 6 8 9];
A.field2 = [5 6 7 8 9];
A.field3 = [23 423 2 4 7];
B.time = [3 7];
B.fieldX = [5 6];
t = unique([A.time, B.time]);
[tf1,loc1] = ismember(A.time, t);
[tf2,loc2] = ismember(B.time, t);
flds = unique([fieldnames(A); fieldnames(B)]);
data = nan(length(flds), length(t));
for ii = 1:length(flds)
if isfield(A, flds{ii})
data(ii,loc1) = A.(flds{ii});
end
if isfield(B, flds{ii})
data(ii,loc2) = B.(flds{ii});
end
end
data = num2cell(data);
C = cell2struct(data, flds, 1);
You didn't specify how you wanted missing values or duplicated times to be treated. So in this example, times without a field value are indicated by NaNs, and any time that has data in both structures simply uses the data from the second one.
2 件のコメント
Kelly Kearney
2016 年 3 月 12 日
No, it would need to be modified a bit. Instead of preallocating data with NaNs, you'd need to set it up as a cell array, and add in a few num2cell's when assigning the numeric arrays to it. I'm away from my computer right now but I'll try to post a modified version later.
参考
カテゴリ
Help Center および File Exchange で Structures についてさらに検索
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!