Accessing field data in nonscalar structure array

13 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);

Categories

Find more on Entering Commands in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!