Accessing field data in nonscalar structure array

10 views (last 30 days)
Let's say I have a nested non-scalar structure array,
Patient(1).Vitals.weight = 185;
Patient(1).Vitals.temperature = [98 96 100 101];
Patient(1).Vitals.mood = {'Good'};
Patient(1).Location.state = 'VA';
Patient(2).Vitals.weight = 203;
Patient(2).Vitals.temperature = [97 97 98 99];
Patient(2).Vitals.mood = {'Fair'};
Patient(2).Location.state = 'NC';
Patient(3).Vitals.weight = 190;
Patient(3).Vitals.temperature = [98 99 99 100];
Patient(3).Vitals.mood = {'Bad'};
Patient(3).Location.state = 'CT';
I would like to acess the data, for example creating (a) a vector containing the weights [185 203 190], (b) a cell array containing the states {'VA', 'NC', 'CT'}, and (c) a matrix containing the temperature values [98 96 100 100; 97 97 98 99; 98 99 99 100]. I want to avoid looping through Patient(1), Patient(2), etc. since my real structure array is large. How do I extract the data? Some failed attempts are listed below.
Patient.Vitals.weight
% Expected one output from a curly brace or dot indexing expression, but there were 2 results.
[Patient.Vitals.weight]
% Expected one output from a curly brace or dot indexing expression, but there were 2 results.
Patient(:).Vitals.weight
% Expected one output from a curly brace or dot indexing expression, but there were 2 results.
Any suggestions? Or is there some other data storage form better suited to data extraction? [I am using multilevel nesting because my real structure is an output of xml2struct, and perhaps I could flatten the results, but then I will lose some data organization.]

Accepted Answer

Daniel M
Daniel M on 18 Nov 2019
Edited: Daniel M on 18 Nov 2019
Here is a solution. You'll have to write the functions differently for gathering cells and arrays.
fun = @(s,field) {s.(field)}; % use {} for string/char
output = fun([Patient.Location],'state');
% ans = 1×3 cell array
% {'VA'} {'NC'} {'CT'}
fun2 = @(s,field) [s.(field)]; % use [] for numbers
output = fun2([Patient.Vitals],'weight');
% ans = 185 203 190
And this even works in R2019b:
f1 = @(s,field) [s.(field)];
f2 = @(s,field,subfield) [f1(s,field).(subfield)];
output = f2(Patient,'Vitals','weight');
% ans = 185 203 190
But this essentially does the same thing as creating a temporary struct, [Patient.Vitals], and then indexing into that. It can just be neatly arranged into an anonymous function.
There is probably also a way to do this with subsref, but it would probably get complex.
  5 Comments
Guillaume
Guillaume on 19 Nov 2019
If your xml schema chan be flattened into one or more table, I would consider using that. But indeed, matlab hasn't got an efficient way of storing xml (or json) data. You could use containers.Map but its implementation in matlab leaves a lot to be desired.
KAE
KAE on 19 Nov 2019
Thanks. Perhaps there is a solution outside Matlab that I can call from within Matlab to access XML data. I will look around.

Sign in to comment.

More Answers (1)

Guillaume
Guillaume on 18 Nov 2019
This is one of the reason I dislike multilevel structures (the other being they're very inefficient memory-wise), there's no easy way to extract all the data from the leaves at once.
The best you can do is probably:
tempvitals = vertcat(Patient.Vitals); %concatenate all the Vitals fields. Note that they must all have the same fields themselves
Weight = vertcat(tempvitals.weight);

Community Treasure Hunt

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

Start Hunting!