61 views (last 30 days)
Show older comments
Daniel Stein on 1 Jun 2023
Edited: Stephen23 on 1 Jun 2023
I have a struct array that each element contains substructures with data that I would like to extract into a numeric array or timeseries. The data structure is set up similar to the example I created below:
dt = 1/1000;
T = 5;
t = 0:dt:T;
data = struct([]);
for it = 1:length(t)
data(it).t = t(it);
data(it).sys = genStruct(t(it));
end
function sOut = genStruct(t)
sOut = struct;
sOut.sys1 = struct;
sOut.sys2 = struct;
sOut.sys1.sub1 = genSubsystemStruct(t);
sOut.sys1.sub2 = genSubsystemStruct(t);
sOut.sys2.sub1 = genSubsystemStruct(t);
sOut.sys2.sub2 = genSubsystemStruct(t);
end
function sOut = genSubsystemStruct(t)
sOut = struct;
sOut.t = t;
sOut.dataPoint1 = randn();
sOut.dataPoint2 = randn();
end
Since data(1:10).sys.sys1.sub1.dataPoint1 does not work, the only method I have found to get an array from this structure is to create a structure map and loop over struct as shown below:
sFieldsOfInterest = struct; % Data map
sFieldsOfInterest.data = ["t"]; % Fields listed under data are saved to a row
sFieldsOfInterest.sys = struct;
sFieldsOfInterest.sys.sys1 = struct('sub1', struct('data', ["dataPoint1", "dataPoint2"]), ...
'sub2', struct('data', ["dataPoint1", "dataPoint2"]));
sFieldsOfInterest.sys.sys2 = struct('sub1', struct('data', ["dataPoint1", "dataPoint2"]), ...
'sub2', struct('data', ["dataPoint1", "dataPoint2"]));
dataArray = [];
for ii = 1:length(data)
dataArray(end+1,:) = getDataFromStructArray(data(ii), sFieldsOfInterest);
end
function row = getDataFromStructArray(dataStruct, structure)
row = [];
f = fields(structure);
for ii = 1:length(f)
if f{ii} == "data"
fois = structure.(f{ii}); % Fields of interest
for foi = fois
row = [row dataStruct.(foi)];
end
else
row = [row getDataFromStructArray(dataStruct.(f{ii}), structure.(f{ii}))];
end
end
end
Is there a better way to access this data? For the most part, the data fields of interest are not multi-dimensional arrays.
0 Comments Show -2 older commentsHide -2 older comments
Show -2 older commentsHide -2 older comments
Sign in to comment.
Sign in to answer this question.
Answers (1)
Stephen23 on 1 Jun 2023
Edited: Stephen23 on 1 Jun 2023
Open in MATLAB Online
"Since data(1:10).sys.sys1.sub1.dataPoint1 does not work.."
First lets generate your sample structure:
dt = 1/1000;
T = 5;
t = 0:dt:T;
data = struct([]);
for it = 1:length(t)
data(it).t = t(it);
data(it).sys = genStruct(t(it));
end
Because all of your nested structures are scalar you can simply use ARRAYFUN:
F = @(s)s.sys.sys1.sub1.dataPoint1;
V = arrayfun(F, data)
V = 1×5001
-1.1297 0.6164 -0.6211 0.3362 0.0718 -0.4912 -0.1255 1.1036 -0.2441 -1.3993 -0.2652 0.0855 1.3243 -1.7874 -0.4221 -1.1474 0.4290 0.0323 -0.1947 -0.4415 0.4525 0.4684 0.4993 -0.3849 -0.7085 0.5279 2.2160 -0.6229 1.3110 -0.6714
Or you could use a few comma-separated lists:
s1 = [data.sys];
s2 = [s1.sys1];
s3 = [s2.sub1];
V = [s3.dataPoint1]
V = 1×5001
-1.1297 0.6164 -0.6211 0.3362 0.0718 -0.4912 -0.1255 1.1036 -0.2441 -1.3993 -0.2652 0.0855 1.3243 -1.7874 -0.4221 -1.1474 0.4290 0.0323 -0.1947 -0.4415 0.4525 0.4684 0.4993 -0.3849 -0.7085 0.5279 2.2160 -0.6229 1.3110 -0.6714
https://www.mathworks.com/help/matlab/matlab_prog/comma-separated-lists.html
https://www.mathworks.com/matlabcentral/answers/1656435-tutorial-comma-separated-lists-and-how-to-use-them
"For the most part, the data fields of interest are not multi-dimensional arrays."
What sizes do you expect the output to be? How do you want them concatenated together?
If using comma-separated lists then you will need to carefully consider using e.g. VERTCAT, HORZCAT, a cell array, ...
You may also find dynamic fieldnames useful:
https://www.mathworks.com/help/matlab/matlab_prog/generate-field-names-from-variables.html
If you want complete flexibility (only gets one field value, but allows any number of nested sturctures, can define all levels and indexing via a cell array i.e. comma-separated list):
https://www.mathworks.com/help/matlab/ref/getfield.html
function sOut = genStruct(t)
sOut = struct;
sOut.sys1 = struct;
sOut.sys2 = struct;
sOut.sys1.sub1 = genSubsystemStruct(t);
sOut.sys1.sub2 = genSubsystemStruct(t);
sOut.sys2.sub1 = genSubsystemStruct(t);
sOut.sys2.sub2 = genSubsystemStruct(t);
end
function sOut = genSubsystemStruct(t)
sOut = struct;
sOut.t = t;
sOut.dataPoint1 = randn();
sOut.dataPoint2 = randn();
end
0 Comments Show -2 older commentsHide -2 older comments
Show -2 older commentsHide -2 older comments
Sign in to comment.
Sign in to answer this question.
An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- Deutsch
- English
- Français
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)
Contact your local office