Accessing data in nested structure arrays

72 views (last 30 days)
Hi everyone,
I'm trying to access data which is nested in a structure array with multiple subfields.
I tried getfield, extractfield and multiple ways to directly access what I need
Example with what I can access easily:
a.b(1).c.d = [1 2 3];
a.b(2).c.d = [3 4 5];
a.b(3).c.d = [5 6 7];
% Direct access
>> [a.b(1).c.d]
ans =
1 2 3
% Field extraction
>> extractfield(a.b(1).c,'d')
ans =
1 2 3
% Field extraction >> only at level below array
>> extractfield(a.b,'c')
ans =
1×3 cell array
{1×1 struct} {1×1 struct} {1×1 struct}
What I' missing now is something like this which results in a vector of the first elements of d for all array entries of b (>> [1 3 5])
[a.b(:).c.d(1)]
>> [1 3 5]
Looking forward to your answers and thanks in advance!
Tim
  1 Comment
Stephen23
Stephen23 on 26 Feb 2021
Edited: Stephen23 on 26 Feb 2021
"Direct access": the square brackets are superfluous because you are not concatenating anything. Get rid of them.
a.b(1).c.d = [1,2,3];
a.b(2).c.d = [3,4,5];
a.b(3).c.d = [5,6,7];
a.b(1).c.d % square brackets removed
ans = 1×3
1 2 3

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 26 Feb 2021
Edited: Stephen23 on 26 Feb 2021
a.b(1).c.d = [1,2,3];
a.b(2).c.d = [3,4,5];
a.b(3).c.d = [5,6,7];
Either
V = arrayfun(@(s)s.c.d(1),a.b)
V = 1×3
1 3 5
Or
tmp = [a.b.c]; % comma-separated list -> concatenate scalar structures
tmp = vertcat(tmp.d); % comma-separated list -> concatenate numeric vectors
V = tmp(:,1)
V = 3×1
1 3 5
  4 Comments
Stephen23
Stephen23 on 18 Jul 2022
Edited: Stephen23 on 18 Jul 2022
@Tim Baur: There is no limit to how many nested levels you can access using structure dot indexing, as long as all of those indices (except the last one) return exactly one array:
S1 = struct('A',{11,12,struct('B',{21,22,struct('C',{31,32,struct('D',{41,42,43})})})})
S1 = 1×3 struct array with fields:
A
S1(3).A(3).B(3).C(3).D % all dot indices return one array
ans = 43
[S1(3).A(3).B(3).C.D] % last dot index returns three arrays
ans = 1×3
41 42 43
As soon as any one of the other indices (not the last dot index) returns multiple items then you are generating comma-separated lists (see answer above) and you must use intermediate variables to collect/concatenate those comma-separated lists into temporary structures:
S2 = struct('A',{...
struct('B',{struct('C',{11,12,13}),struct('C',{21,22,23})}),...
struct('B',{struct('C',{31,32,33}),struct('C',{41,42,43})})});
tmp = [S2.A] % [two (1x2 structure) arrays]
tmp = 1×4 struct array with fields:
B
tmp = [tmp(1:2).B] % [two (1x3 structure) arrays]
tmp = 1×6 struct array with fields:
C
[tmp.C] % [six (1x1 numeric) arrays]
ans = 1×6
11 12 13 21 22 23
There is no specific rule for what level you need to do this at, because it depends entirely on how many (nested structure) arrays are returned by each dot index (which is not fixed, because the linear/subscript indexing can change as well as the size of the structure). Note that you can use GETFIELD to access one value of an arbitrarily nested structure:
getfield(S1,{3},'A',{3},'B',{3},'C',{3},'D')
ans = 43
While this can only get one field value, you can easily call it multiple times in a loop. Or you could write your own loop which simply keep concatenating the intermediate structures (i.e. no special treatment of comma-separated lists which only return one array) and uses your desired indexing at each level:
C = {'A','B','C';... cell array of fields and linear indices
1:2,1:2,4:5};
tmp = [S2(C{2,1}).(C{1,1})];
for k = 2:size(C,2)
tmp = [tmp(C{2,k}).(C{1,k})];
end
display(tmp)
tmp = 1×2
21 22
Note that the indexing refers to the concatenated arrays, not the ones in the nested structure tree.

Sign in to comment.

More Answers (0)

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!