Create array of “deep” struct (scalar) fields

4 views (last 30 days)
Jorge
Jorge on 11 Aug 2019
Answered: Jorge on 12 Aug 2019
Hi! How can I collapse the values of "deep" struct fields into arrays by just indexing?
In the example below, I can only do it for the "top-most" level, and for "deeper" levels I get the error:
"Expected one output from a curly brace or dot indexing expression, but there were XXX results."
The only workaround I found so far is to unfold the operation into several steps, but the deeper the structure the uglier this gets.
clc; clear variables;
% Dummy data
my_struc.points(1).fieldA = 100;
my_struc.points(2).fieldA = 200;
my_struc.points(3).fieldA = 300;
my_struc.points(1).fieldB.subfieldM = 10;
my_struc.points(2).fieldB.subfieldM = 20;
my_struc.points(3).fieldB.subfieldM = 30;
my_struc.points(1).fieldC.subfieldN.subsubfieldZ = 1;
my_struc.points(2).fieldC.subfieldN.subsubfieldZ = 2;
my_struc.points(3).fieldC.subfieldN.subsubfieldZ = 3;
my_struc.info = 'Note my_struc has other fields besides "points"';
% Get all fieldA values by just indexing (this works):
all_fieldA_values = [my_struc.points(:).fieldA]
% Get all subfieldM values by just indexing (doesn't work):
% all_subfieldM_values = [my_struc.points(:).fieldB.subfieldM]
% Ugly workaround:
temp_array_of_structs = [my_struc.points(:).fieldB];
all_subfieldM_values = [temp_array_of_structs.subfieldM]
% Get all subsubfieldZ values by just indexing (doesn't work):
% all_subsubfieldZ_values = [my_struc.points(:).fieldC.subfieldN.subsubfieldZ]
% Ugly workaround:
temp_array_of_structs1 = [my_struc.points(:).fieldC];
temp_array_of_structs2 = [temp_array_of_structs1.subfieldN];
all_subsubfieldZ_values = [temp_array_of_structs2.subsubfieldZ]
Output:
all_fieldA_values =
100 200 300
all_subfieldM_values =
10 20 30
all_subsubfieldZ_values =
1 2 3
Thanks for any help!

Accepted Answer

Jorge
Jorge on 12 Aug 2019
Thanks for the answers & comments; turns out it's possible to use arrayfun() to this purpose!:
all_subfieldM_values = arrayfun(@(in) in.fieldB.subfieldM, my_struc.points)
all_subsubfieldZ_values = arrayfun(@(in) in.fieldC.subfieldN.subsubfieldZ, my_struc.points)
This achieves the desired effect with a single line of code :)

More Answers (1)

TADA
TADA on 11 Aug 2019
As always, you can use a small utility function to drill down the object hierarchy
It's probably not the most elegant solution because you have to write the field names as strings, so don't expect any intellisence there, but hey, subsref does the same thing so...
function b = drillref(a, s)
fields = strsplit(s, '.');
b = a;
for i = 1:numel(fields)
b = [b.(fields{i})];
end
end
A = drillref(my_struc, 'points.fieldA')
A =
100 200 300
B_M = drillref(my_struc, 'points.fieldB.subfieldM')
B_M =
10 20 30
C_N_Z = drillref(my_struc, 'points.fieldC.subfieldN.subsubfieldZ')
C_N_Z =
1 2 3

Categories

Find more on Structures in Help Center and File Exchange

Products


Release

R2018a

Community Treasure Hunt

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

Start Hunting!