2

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!

4
  • 1
    [my_struc.points(:).fieldA] is the same as [my_struc.points.fieldA]. Commented Aug 11, 2019 at 13:15
  • 1
    "but the deeper the structure the uglier this gets" -> Deep structures are ugly. Avoid using them, then you will avoid this problem! :) Commented Aug 11, 2019 at 13:16
  • Indeed. In particular, I haven't found a way to initialize them outside loops where their data (e.g. the "points(:)" fields in the example) is generated, so currently they are growing inside the loop! Is there a way to get around this? I know in advance how many points I'll have, but each one has a complex subfields hierarchy so initialization by hand is not an option, I guess... :( Commented Aug 12, 2019 at 9:49
  • 1
    If they all have the same subfield hierarchy, you can create one of them, then use deal to assign the same template to all points: [my_struct.points(1:N)] = deal(template). Commented Aug 12, 2019 at 12:26

1 Answer 1

1

You can use arrayfun to have acces to each individual 'point', and then acces its data. This will return an array with the same dimensions as my_struc.points:

all_subfieldM_values = arrayfun(@(in) in.fieldB.subfieldM, my_struc.points)
all_subsubfieldZ_values = arrayfun(@(in) in.fieldC.subfieldN.subsubfieldZ, my_struc.points)

Not optimal, but at least it's one line.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.